/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}

/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}

/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
/* 
  $Id: DETextCtrl.cpp 25 2009-11-28 00:34:01Z krkim $ $Revision: 25 $
  $HeadURL: http://krkim-laptop/svn/DuruEdit/Src/DEEditDLL/DETextCtrl.cpp $
 */

#include "stdafx.h"
#include "DEStructs.h"
#include "DETextCtrl.h"
#include "langs.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
DETextCtrl::DETextCtrl()
{
	m_cf.arDBCSWidth=NULL;
	m_cf.pLine=NULL;
	m_cf.hBit=NULL;
	m_cf.Parser=NULL;
	m_cf.bFindSelect=FALSE;
	m_cf.ViewMode=TEXT_VIEW; 
	m_cf.Bklogfont.lfHeight=-1;
	m_cf.bShowCursor=TRUE;

	::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(LOGFONT),&m_cf.logfont);
}

BOOL DETextCtrl::Create(int x,int y,int w,int h,DWORD style,UINT id,HWND hParent)
{
	DWORD dwStyle = style | WS_CLIPCHILDREN;//WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
	CreateEx(0,"DETextCtrl",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL DETextCtrl::PreCreateWindow(CREATESTRUCT &cs)
{
	{	//make sure the default window class is registered
#if 0
		char *classname="XFCWndClass";
		WNDCLASSEX wcex;
		wcex.cbSize = sizeof (WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		//m_wcex.lpfnWndProc = (WNDPROC) ::DefWindowProc;// default SDK window procedure: 
		wcex.lpfnWndProc = (WNDPROC) ::XFCWndProc;// default SDK window procedure: 
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = XFCGetInstanceHandle();           // owner of the class: mandatory
		wcex.hIcon = NULL;//LoadIcon (m_hInstance, classname);
		//wcex.hIcon = LoadIcon(XFCGetInstanceHandle(), (LPCTSTR)IDI_MAINICON);
		wcex.hIconSm = NULL;//LoadIcon (m_hInstance, "SMALL");
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//wcex.hbrBackground = (HBRUSH) COLOR_BTNFACE;//(COLOR_WINDOW+1) ; // optional
		wcex.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);

		wcex.lpszMenuName = cs.lpszClass;
		wcex.lpszClassName = cs.lpszClass;   // mandatory
		
		RegisterWndClass(wcex);
		//cs.lpszClass = classname;
#endif
	}
	return KFCWnd::PreCreateWindow(cs);
}

void DETextCtrl::RegisterWndClass(WNDCLASSEX &wcex)
{
	wcex.hCursor = LoadCursor(NULL,IDC_IBEAM);//set default cursor shape here***********
	wcex.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
	KFCWnd::RegisterWndClass(wcex);
}

///////////////////////////////////////////////////////////////////////////////////
// KFC Message Handler

BOOL DETextCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HINSTANCE hInst = KFCGetInstanceHandle();

	m_cf.bComp=FALSE;
	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	m_cf.SelStartLine=0;
	m_cf.bDragSel=FALSE;
	m_cf.SumDelta=0;
	m_cf.bHideCaret=FALSE;
#ifdef USE_SKINSCROLLBAR
	m_sbH.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ,0,0,0,0,m_hWnd,AEID_HORZSCROLL);
	m_sbV.Create(WS_CHILD | WS_VISIBLE | SBS_VERT,0,0,0,0,m_hWnd,AEID_VERTSCROLL);

	CHAR szImageFile[_MAX_PATH];
	GetModuleFileName(NULL,szImageFile,sizeof(szImageFile));

	CHAR *p = strrchr(szImageFile,'\\');
	if(p) strcpy(p+1,"SkinBar.bmp");
	m_sbH.SetBitmap(szImageFile);
	m_sbV.SetBitmap(szImageFile);
	m_sbHorz = m_sbH.GetSafeHwnd();
	m_sbVert = m_sbV.GetSafeHwnd();
	//m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);

#else
	m_sbVert=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_VERT,
		0,0,0,0,m_hWnd,(HMENU)AEID_VERTSCROLL,hInst,NULL);
	m_sbHorz=CreateWindow("scrollbar",NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
		0,0,0,0,m_hWnd,(HMENU)AEID_HORZSCROLL,hInst,NULL);
#endif
	//m_cf.hBtnSetting=CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	//	0,0,0,0,m_hWnd,(HMENU)AEID_BTNSETTING,hInst,NULL);

	SetDefaultSetting();
	m_cf.bVertSplit=TRUE;
	m_cf.bHorzSplit=TRUE;
	InitView();

	m_cf.lpDx=(int *)malloc(1025*sizeof(int));
	return TRUE;	
}

BOOL DETextCtrl::OnClose()
{
	return 0;
}

void DETextCtrl::OnDestroy()
{
	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
		m_cf.arDBCSWidth=NULL;
	}
	if (m_cf.pLine) {
		free(m_cf.pLine);
		m_cf.pLine=NULL;
	}
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	SetParser(-1);
	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
	}
	free(m_cf.lpDx);
}

void DETextCtrl::OnPaint()
{
	KFCPaintDC dc(m_hWnd);
	HDC hDC = dc.GetSafeHdc();

	HDC hMemDC;
	int l,l2;
	int s,e,t,e2;
	HBRUSH hBrush;
	HBITMAP OldBitmap;
	RECT lrt;
	HBRUSH hMarBrush;
	RECT mrt;
	HPEN hMarPen,OldPen;
	HFONT hOldFont;
	RECT crt,srt;
	HBRUSH hInnerBrush;
	int RulerHeight;

	RECT rcClip;
	if(GetClipBox(hDC,&rcClip) == ERROR) return;

	SetBkMode(hDC,TRANSPARENT);
	GetClientRect(m_hWnd,&crt);

	if (m_pEF->TestEditStyle(AES_SHOWRULER)) {
		DrawRuler(m_hWnd,hDC);
		RulerHeight = RULERHEIGHT;
	} else
		RulerHeight = 0;

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);
	hInnerBrush = CreateSolidBrush(credge);
	//위, 오른쪽 여백 그림
	if (m_pEF->InnerRect.top) {
		SetRect(&mrt,m_cf.MarginWidth,RulerHeight,crt.right-SBW,m_cf.frt.top);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	if (m_pEF->InnerRect.right) {
		SetRect(&mrt,m_cf.frt.right,RulerHeight,crt.right-SBW,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}

	t=m_cf.yPos/m_cf.LineHeight;
	s=max((m_cf.yPos+PureY(rcClip.top))/m_cf.LineHeight,t);
	e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	e2=e=max((m_cf.yPos+PureY(rcClip.bottom)-1)/m_cf.LineHeight,t);
	if (m_cf.ViewMode == TEXT_VIEW) {
		e=min(e,m_cf.TotalLine-1);
		m_cf.Parser->ParseLines(*this,e);
	} else {
		e=min(e,GetRowCount()-1);
	}
	
	hMemDC = CreateCompatibleDC(hDC);
	SetBkMode(hMemDC,TRANSPARENT);
	if (m_cf.hBit == NULL) {
		m_cf.hBit=CreateCompatibleBitmap(hDC,m_cf.frt.right,m_cf.LineHeight);
	}
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_cf.hBit);

	if (m_cf.hMainFont) {
		hOldFont=(HFONT)SelectObject(hMemDC,m_cf.hMainFont);
	}

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	hBrush=CreateSolidBrush(crbkg);
	SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
	/* 1라인분만 MemDC 할당하였기 때문에 dc 시작위치는 left,top 0 이다.*/
	for (l = s ; l <= e ; l++) {
		FillRect(hMemDC,&lrt,hBrush);
		DrawLine(hMemDC,l);
		BitBlt(hDC,0,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.LineHeight,
			hMemDC,0,0,SRCCOPY);
	}

	if(m_pEF->TestEditStyle(AES_SHOWMARGIN)){
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);//마진 배경
		//t ~ l 까지 라인 마진 배경
		SetRect(&mrt,0,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.MarginWidth,crt.bottom-SBW);
		FillRect(hDC,&mrt,hMarBrush);
		//첫줄 위쪽 마진
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			SetRect(&mrt,0,RULERHEIGHT,m_cf.MarginWidth,m_cf.frt.top);
		else
			SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.frt.top);
		FillRect(hDC,&mrt,hMarBrush);

		hMarPen=CreatePen(PS_SOLID,1, crmarpen);//마진 선색
		OldPen=(HPEN)SelectObject(hDC,hMarPen);
		// 마진 구분선은 처음부터 끝까지 그음
		if(m_pEF->TestEditStyle(AES_SHOWRULER))
			MoveToEx(hDC,m_cf.MarginWidth-1,RULERHEIGHT,NULL);
		else
			MoveToEx(hDC,m_cf.MarginWidth-1,0,NULL);
		LineTo(hDC,m_cf.MarginWidth-1,crt.bottom-SBW);

		SelectObject(hDC,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);
	}
	SetRect(&lrt,m_cf.frt.left,DocY((l-t)*m_cf.LineHeight),m_cf.frt.right,m_cf.frt.bottom);	
	FillRect(hDC,&lrt,hBrush);
	
	// 문서 뒷부분의 배경 비트맵을 그린다.
	if (m_pEF->hBackBit) {
		SetRect(&lrt,m_cf.MarginWidth,0,m_cf.frt.right,m_cf.LineHeight);
		for (l2=l;l2<=e2;l2++) {
			FillRect(hMemDC,&lrt,hBrush);
			DrawBackBit(hMemDC,l2);
			BitBlt(hDC,m_cf.frt.left,(l2-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,
				(l2-t)*m_cf.LineHeight+m_cf.LineHeight+m_cf.frt.top,hMemDC,m_cf.frt.left,0,SRCCOPY);
		}
	} else {
		SetRect(&lrt,m_cf.frt.left,(l-t)*m_cf.LineHeight+m_cf.frt.top,m_cf.frt.right,m_cf.frt.bottom);
		FillRect(hDC,&lrt,hBrush);
	}

	// 문서 뒷부분의 왼쪽 여백 그림. 더블 버퍼링되지 않으므로 직접 그려야 한다.
	if (m_pEF->InnerRect.left) {
		SetRect(&mrt,m_cf.MarginWidth,DocY((l-t)*m_cf.LineHeight),m_cf.frt.left,m_cf.frt.bottom);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 아래 여백 그림
	if (m_pEF->InnerRect.bottom) {
		SetRect(&mrt,m_cf.MarginWidth,m_cf.frt.bottom,m_cf.frt.right,crt.bottom-SBW);
		FillRect(hDC,&mrt,hInnerBrush);
	}
	// 안쪽 브러시 파괴
	DeleteObject(hInnerBrush);

	if (m_cf.hMainFont) {
		SelectObject(hMemDC,hOldFont);
	}
	DeleteObject(hBrush);
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
	
	// 스플릿 박스를 그린다.
	hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

	COLORREF crSplitBox = RGB(192,210,220);
	if (m_cf.bVertSplit) {
		SetRect(&srt,crt.right-SBW,crt.top,crt.right,crt.top+SPLITWIDTH);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	if (m_cf.bHorzSplit) {
		SetRect(&srt,crt.left,crt.bottom-SBW,crt.left+SPLITWIDTH,crt.bottom);
		//DrawFrameControl(hDC,&srt,DFC_BUTTON,DFCS_BUTTONPUSH);
		FillRect(hDC,&srt,hBrush);
		dc.Draw3dRect(&srt,crSplitBox,crSplitBox);//GetSysColor(COLOR_3DDKSHADOW), GetSysColor(COLOR_3DDKSHADOW));
	}
	DeleteObject(hBrush);

	if (m_cf.SelStart!=m_cf.SelEnd && m_pEF->SelBlockType==2) {
		DrawSelFrame(hDC);
	}
	RECT rcEdge;

	GetClientRect(m_hWnd,&rcEdge);

	rcEdge.top = rcEdge.bottom - SBW;
	rcEdge.left = rcEdge.right - SBW;
	m_sbV.DrawEdge(hDC,rcEdge,0);
}

BOOL DETextCtrl::OnEraseBkgnd(HDC hDC)
{
	//직접 배경그리려면 TRUE리턴,시스템이 그리길 원하면 Default Window 프로시듀어가 작동되도록 FALSE를 리턴한다.
	//다른창이 가려지면 텍스트 일부가 깨진후 복원이 안되는 것때문.이때 bErase = FALSE여야 재귀호출안될것.
	//Call InvalidateRect to redraw entire text because some text is broken when the area hiden by other window will be appearing.
	::InvalidateRect(m_hWnd, NULL, FALSE);
	return TRUE;
}

BOOL DETextCtrl::OnDrawItem(const DRAWITEMSTRUCT * lpDrawItem)
{
	//If an application processes this message, it should return TRUE. 
	//By default, the DefWindowProc function draws the focus rectangle for an owner-drawn list box item. 
	return 0;
}

void DETextCtrl::OnTimer(UINT_PTR nIDEvent)
{
	POINT pt;

	switch (nIDEvent) {
	case 1:
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		SendMessage(m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
		break;
	}
}

BOOL DETextCtrl::OnSize(UINT state, int cx, int cy)
{
	int nPara;
	int nLine;
	int toff;
	int r,c;
	RECT crt;
	int sw = SBW;
	if (state != SIZE_MINIMIZED) {
		GetClientRect(m_hWnd,&crt);
		m_cf.frt=crt;
		// 스크롤 바 영역과 안쪽 여백은 편집 영역에서 제외된다.
		m_cf.frt.right-=(SBW+m_pEF->InnerRect.right);
		m_cf.frt.bottom-=(SBW+m_pEF->InnerRect.bottom);
		m_cf.frt.left+=(m_cf.MarginWidth+m_pEF->InnerRect.left);
		m_cf.frt.top+=(m_pEF->InnerRect.top+(m_pEF->TestEditStyle(AES_SHOWRULER) ? RULERHEIGHT:0));
		// 포맷팅 영역의 폭과 높이를 미리 구해 놓는다.
		m_cf.Fwidth=m_cf.frt.right-m_cf.frt.left;
		m_cf.Fheight=m_cf.frt.bottom-m_cf.frt.top;
		// 분할 가능하면 스크롤 바 위, 왼쪽에 스플릿 박스를 위한 여백을 남긴다.
		if (m_cf.bVertSplit) {
			//::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SBW-SPLITWIDTH,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,SPLITWIDTH,SBW,crt.bottom-SPLITWIDTH,TRUE);
		} else {
			//::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom-SBW,TRUE);
			::MoveWindow(m_sbVert,crt.right-SBW,0,SBW,crt.bottom,TRUE);
		}
		if (m_cf.bHorzSplit) {
			::MoveWindow(m_sbHorz,SPLITWIDTH,crt.bottom-SBW,
				crt.right-SBW-SPLITWIDTH,SBW,TRUE);
		} else {
			::MoveWindow(m_sbHorz,0,crt.bottom-SBW,crt.right-SBW,SBW,TRUE);
		}
		//::MoveWindow(m_cf.hBtnSetting,crt.right-SBW,crt.bottom-SBW,SBW,SBW,TRUE);

		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			nPara=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nPara;
			nLine=m_cf.pLine[m_cf.yPos/m_cf.LineHeight].nLine;
			toff=GetOffFromPara(nPara,0);
			UpdateLineInfo();
		}
		UpdateScrollInfo();
		if (m_cf.nWrap && m_cf.ViewMode == TEXT_VIEW) {
			GetRCFromOff(toff,r,c);
			m_cf.yPos=(r+nLine)*m_cf.LineHeight;
			m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		}
		if (GetFocus()==m_hWnd) {
			SetCaret(TRUE,FALSE);
		}
		if (m_cf.hBit) {
			DeleteObject(m_cf.hBit);
			m_cf.hBit=NULL;
		}
	}
	return 0;
}

UINT DETextCtrl::OnGetDlgCode(LPMSG lpMsg)
{
	if(lpMsg) {
		if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam=='\t' && (m_pEF->TestEditStyle(AES_WANTTAB) == FALSE))
			return 0;
	}
	return DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
}

BOOL DETextCtrl::OnCommand(UINT nID, HWND hWndCtrl, UINT nNotifyCode)
{
	//if nID == 1 ,IDOK or ENTER key
	//nNotifyCode == Notify message  from an accelerator = 1,from a menu = 0
	//hWndCtrl = from a control = ctrl handle Otherwise  = NULL

	HGLOBAL hmem;
	TCHAR *ptr;
	int SelFirst, SelSecond;
	TCHAR *ptr2;
	HGLOBAL hmem2;
	int len,idx,linelen,len2;
	switch(nID){
	//case IDOK:
	//case IDCANCEL:
	//	EndDialog(m_hWnd,nID);
	//	break;
	case IDM_AE_CUT:
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("cut");
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPY:
		if (m_cf.SelStart != m_cf.SelEnd) {
			m_cmdH.pushCmd("copy");
			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, SelSecond-SelFirst+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				memcpy(ptr,m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len=MakeSelTable();
				hmem=GlobalAlloc(GHND, len+1);
				ptr=(TCHAR *)GlobalLock(hmem);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr+=linelen;
					*ptr++='\r';
					*ptr++='\n';
				}
				*ptr=0;
				GlobalUnlock(hmem);

				hmem2=GlobalAlloc(GHND, len+1);
				ptr2=(TCHAR *)GlobalLock(hmem2);
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++=0;
				}

				*ptr2=(TCHAR)0xff;
				GlobalUnlock(hmem2);
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					CloseClipboard();
				}
			}
		}
		break;
	case IDM_AE_PASTE:
		BOOL bPrevSel;
		if (IsClipboardFormatAvailable(CF_TEXT) && m_pEF->bReadOnly==FALSE && 
			m_cf.bCapture==FALSE) {
			m_cmdH.pushCmd("paste");
			if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(DEEditCtrl::AeColFormat);
				ptr=(TCHAR *)GlobalLock(hmem);
				m_pEF->StartUndoGroup(17);
				DeleteSelection();
				PasteColumn(m_cf.off,m_cf.ExtraX,ptr);
				m_pEF->EndUndoGroup();
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
			} else {
				InputExtraSpace(m_cf.off);
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					m_pEF->StartUndoGroup(25);
				}
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_pEF->StartUndoGroup(2);
				}
				bPrevSel=DeleteSelection();
				OpenClipboard(m_hWnd);
				hmem=GetClipboardData(CF_TEXT);
				ptr=(TCHAR *)GlobalLock(hmem);
				Insert(m_cf.off,ptr,lstrlen(ptr));

				if (bPrevSel) {
					m_pEF->EndUndoGroup();
				}
				GlobalUnlock(hmem);
				CloseClipboard();
				Invalidate(m_pEF->FindParaStart(m_cf.off));
				SelFirst=m_cf.off;
				m_cf.off += lstrlen(ptr);
				SelSecond=m_cf.off;
				if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
					AdjustSpaceInsert(SelFirst,SelSecond);
					m_cf.off=SelSecond;
					m_pEF->EndUndoGroup();
				}
			}
			SetCaret();
		}
		break;
	case IDM_AE_SELALL:
		m_cmdH.pushCmd("select doc");
		if (m_cf.bColumnMode) {
			SetColumnMode(FALSE);
		}
		m_cf.SelStart=0;
		m_cf.SelEnd=m_pEF->doclen;
		m_cf.off=m_cf.SelEnd;
		Invalidate(-1);
		SetCaret();
		break;
	case IDM_AE_CUTAPPEND:
		m_cmdH.pushCmd("cutapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd && m_pEF->bReadOnly==FALSE && m_cf.bCapture==FALSE) {
			m_cmdH.runlevel++;
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPYAPPEND,0),0);
			m_cmdH.runlevel--;
			DeleteSelection();
			Invalidate(m_pEF->FindParaStart(m_cf.off));
			SetCaret();
		}
		break;
	case IDM_AE_COPYAPPEND:
		m_cmdH.pushCmd("copyapp");
		if (!IsClipboardFormatAvailable(CF_TEXT)) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
			break;
		}
		if (m_cf.SelStart != m_cf.SelEnd) {
			OpenClipboard(m_hWnd);
			hmem=GetClipboardData(CF_TEXT);
			ptr=(TCHAR *)GlobalLock(hmem);
			GlobalUnlock(hmem);
			CloseClipboard();

			if (!m_cf.bColumnMode) {
				SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
				SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
				hmem=GlobalAlloc(GHND, lstrlen(ptr)+SelSecond-SelFirst+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				memcpy(ptr2+lstrlen(ptr2),m_pEF->buf+SelFirst,SelSecond-SelFirst);
				GlobalUnlock(hmem);
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					CloseClipboard();
				}
			} else {
				len2=lstrlen(ptr);
				len=MakeSelTable();

				hmem=GlobalAlloc(GHND,len2+len+1);
				ptr2=(TCHAR *)GlobalLock(hmem);
				lstrcpy(ptr2,ptr);
				ptr2+=len2;
				for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
					linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
					memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
					ptr2+=linelen;
					*ptr2++='\r';
					*ptr2++='\n';
				}
				*ptr2=0;
				GlobalUnlock(hmem);

				if (IsClipboardFormatAvailable(DEEditCtrl::AeColFormat)) {
					OpenClipboard(m_hWnd);
					hmem2=GetClipboardData(DEEditCtrl::AeColFormat);
					ptr=(TCHAR *)GlobalLock(hmem2);
					GlobalUnlock(hmem2);
					CloseClipboard();
					len2=0;
					ptr2=ptr;
					while (*ptr2!=(TCHAR)0xff) {
						len2++;
						ptr2++;
					}

					hmem2=GlobalAlloc(GHND,len2+len+1);
					ptr2=(TCHAR *)GlobalLock(hmem2);
					memcpy(ptr2,ptr,len2);
					ptr2+=len2;
					for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
						linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
						memcpy(ptr2,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
						ptr2+=linelen;
						*ptr2++=0;
					}
					*ptr2=(TCHAR)0xff;
					GlobalUnlock(hmem2);
				} else {
					hmem2=NULL;
				}
				FreeSelTable();
				if (OpenClipboard(m_hWnd)) {
					EmptyClipboard();
					SetClipboardData(CF_TEXT,hmem);
					if (hmem2) {
						SetClipboardData(DEEditCtrl::AeColFormat,hmem2);
					}
					CloseClipboard();
				}
			}
		}
		break;
	default:
		SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+5,nID,0);
		return 0;//0 pass to default procedure
	}
	return 0;//0 to default
}

void DETextCtrl::OnSetFocus(HWND hwndOldFocus)
{
	// 차일드가 포커스를 가진 상태에서 파괴될 때 부모가 정리되는 중에  
	// WM_SEFOCUS가 날라오는데 이때는 무시한다.
	if(m_cf.pLine == NULL) return;
	SetCaret(FALSE,FALSE);

	if ((m_pEF->HideSelType != 2 &&m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
	m_pEF->ChangeActiveView(this,0);
}

void DETextCtrl::OnKillFocus(HWND hwndNewFocus)
{
	EndComp();
	DestroyCaret();

	if ((m_pEF->HideSelType != 2 && m_cf.SelStart != m_cf.SelEnd) ||
		(m_pEF->TestEditStyle(AES_HIDECURLINE) == TRUE && m_pEF->nShowCurLine != 0)) {
		Invalidate(-1);
	}
}

BOOL DETextCtrl::OnSetCursor(HWND hWndCursor,UINT nHitTest,UINT message)
{
	POINT pt;
	RECT crt;

	GetClientRect(m_hWnd,&crt);
	GetCursorPos(&pt);
	ScreenToClient(&pt);

	if (nHitTest == HTCLIENT) {
		if (pt.x < m_cf.MarginWidth && pt.y < crt.bottom-SBW) {
			SetCursor(DEEditCtrl::hCMargin);
			return TRUE;
		}

		// 수직 스플릿 박스의 커서
		if (m_cf.bVertSplit && pt.x > crt.right-SBW && pt.y < SPLITWIDTH) {
			SetCursor(LoadCursor(NULL,IDC_SIZENS));
			return TRUE;
		}

		// 수평 스클릿 박스의 커서
		if (m_cf.bHorzSplit && pt.x < SPLITWIDTH && pt.y > crt.bottom-SBW) {
			SetCursor(LoadCursor(NULL,IDC_SIZEWE));
			return TRUE;
		}

		// 사용금지된 스크롤 바 위에서의 화살표 커서를 표시한다.
		if (pt.y > crt.bottom-SBW || pt.x > crt.right-SBW) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		// 눈금자 위에서는 화살표 커서를 표시한다.
		if (m_pEF->TestEditStyle(AES_SHOWRULER) && pt.y < RULERHEIGHT) {
			SetCursor(LoadCursor(NULL,IDC_ARROW));
			return TRUE;
		}

		pt.x += m_cf.xPos;
		pt.y += m_cf.yPos;
		if (IsInSelection(pt.x, pt.y)) {
			SetCursor(DEEditCtrl::hCSel);
			return TRUE;
		}
	}

	return FALSE;//Nonzero to halt further processing, or 0 to continue DefWindowProc.
}

BOOL DETextCtrl::OnLButtonDown(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	int SelFirst, SelSecond;
	RECT crt;
	
	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,0,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
			return 1;
		}

		if (bShift) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_cf.SelStart == m_cf.SelEnd) {
				GetRCFromOff(m_cf.off,nr,c);
			} else {
				if (toff > SelFirst) {
					GetRCFromOff(SelFirst,nr,c);
				} else {
					GetRCFromOff(SelSecond,nr,c);
				}
			}
			m_cf.SelStartLine=nr;

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			m_cf.SelStart=m_cf.pLine[r].begoff;;
			m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			m_cf.SelStartLine=r;
		}
		SetCaret();
		Invalidate(-1);
		m_cf.bSelLine=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		return 1;
	}

	if (bShift) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		ClearSelection();
		m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		m_cf.SelStart=m_cf.SelEnd=m_cf.off;
	}

	SetCapture(m_hWnd);
	m_cf.bCapture=TRUE;
	SetCaret();
	return 1;
}

BOOL DETextCtrl::OnLButtonUp(UINT nFlags,POINT point)
{
	BOOL bControl;
	int SelLen;
	int toff;
	HIMC hImc;

	m_cf.bCapture=FALSE;
	m_cf.bSelLine=FALSE;
	ReleaseCapture();
	KillTimer(m_hWnd,1);
	hImc=ImmGetContext(m_hWnd);
	ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_CANCEL,0);
	ImmReleaseContext(m_hWnd,hImc );

	// 창 분할중이었으면 분할을 종료한다.
	if (EndSplit(m_hWnd,point)) {
		return 1;
	}
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		m_cf.bDragSel=FALSE;
		if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos)==TRUE) {
			m_cf.off=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			SetCaret();
			m_cf.SelStart=m_cf.SelEnd=0;
			Invalidate(-1);
		} else {
			if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
				SelLen=abs(m_cf.SelStart-m_cf.SelEnd);
				toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
				if (m_cf.bColumnMode) {
					ColumnCopyString(bControl,toff,m_cf.ExtraX);
					return 1;
				} else {
					CopyString(bControl,min(m_cf.SelStart,m_cf.SelEnd),toff,SelLen);
				}

				m_cf.SelStart=toff;
				m_cf.SelEnd=m_cf.SelStart+SelLen;
				m_cf.off=m_cf.SelEnd;
				SetCaret();
				Invalidate(-1);
			} else {
				SetCaret();
			}
		}
	}
	return 1;
}

BOOL DETextCtrl::OnLButtonDblClk(UINT nFlags,POINT point)
{
	int toff;
	BOOL bShift, bControl;
	int r,c;
	int nr;
	RECT crt;

	ShowCursorEdit(TRUE);
	GetClientRect(m_hWnd,&crt);
	// 스플릿 박스 위면 창 분할을 시작한다.
	if (StartSplit(m_hWnd,1,point)) {
		return 1;
	}
	// 사용금지된 스크롤 바 위에서의 클릭은 무시한다.
	if (point.y > crt.bottom-SBW || point.x > crt.right-SBW) {
		return 1;
	}

	// 눈금자 위에서의 클릭은 무시한다.
	if (m_pEF->TestEditStyle(AES_SHOWRULER) && point.y < RULERHEIGHT) {
		return 1;
	}

	m_cf.bFindSelect=FALSE;
	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	::SetFocus(m_hWnd);

	if (IsInSelection(point.x+m_cf.xPos, point.y+m_cf.yPos) && m_pEF->bReadOnly==FALSE && m_pEF->TestEditStyle(AES_ALLOWDRAG)) {
		m_cf.bDragSel=TRUE;
		SetCapture(m_hWnd);
		m_cf.bCapture=TRUE;
		DestroyCaret();
		CreateCaret(m_hWnd,(HBITMAP)1,2,m_cf.FontHeight);
		ShowCaret(m_hWnd);
		return 1;
	}

	if (point.x < m_cf.MarginWidth) {
		toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
		GetRCFromOff(toff,r,c);
		while (m_cf.pLine[r].nLine!=0) r--;
		for (nr=r+1;;nr++) {
			if (nr == m_cf.TotalLine || m_cf.pLine[nr].nLine == 0) {
				break;
			}
		}
		nr--;

		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[nr].endoff);
		SetCaret();
		Invalidate(-1);
		return 1;
	}

	toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
	GetNowWord(toff,m_cf.SelStart,m_cf.SelEnd);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd;
		SetCaret();
		Invalidate(-1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseMove(UINT nFlags,POINT point)
{
	BOOL bInstTimer;
	int r,c;
	int OldOff;
	int toff;
	BOOL bControl;
	int sx,sy;

	ShowCursorEdit(TRUE);
	if (m_cf.bCapture == FALSE) {
		return 1;
	}
	// 창 분할중이면 분할을 처리한다.
	if (Spliting(m_hWnd,point)) {
		return 1;
	}

	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);
	if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
		bControl=!bControl;
	}

	if (m_cf.bDragSel) {
		if (point.x > m_cf.frt.left && point.x < m_cf.frt.right && point.y > m_cf.frt.top && point.y < m_cf.frt.bottom) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetXYFromOff(toff,sx,sy);
			SetCaretPos(sx-m_cf.xPos,sy-m_cf.yPos+GetCharYPos());
			if (bControl) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		} else {
			SetCursor(DEEditCtrl::hCNoDrop);
		}
	} else {
		OldOff=m_cf.off;
		if (m_cf.bSelLine) {
			toff=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			GetRCFromOff(toff,r,c);

			if (r >= m_cf.SelStartLine) {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].begoff;
				m_cf.off=m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
			} else {
				m_cf.SelStart=m_cf.pLine[m_cf.SelStartLine].endoff;
				m_cf.off=m_cf.SelEnd=m_cf.pLine[r].begoff;
			}
		} else {
			// 선택 중에는 가상 위치로 벗어날 수 없음. 단, 컬럼 모드일 때는 예외
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt++;
			}
			m_cf.off=m_cf.SelEnd=GetOffFromXY(point.x+m_cf.xPos,point.y+m_cf.yPos);
			if (!m_cf.bColumnMode) {
				m_cf.ignoreVirt--;
			} else {
				m_cf.SelExtraX=m_cf.ExtraX;
			}
		}
		SetCaret();
		Invalidate(min(OldOff,m_cf.off),max(OldOff,m_cf.off));
		if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
			Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		}
	}
	
	bInstTimer=FALSE;
	if (point.y>m_cf.frt.bottom) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
		bInstTimer=TRUE;
	}
	if (point.y < m_cf.frt.top) {
		SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
		bInstTimer=TRUE;
	}
	if (m_cf.nWrap == 0) {
		GetRCFromOff(m_cf.SelEnd,r,c);
		if (point.x>m_cf.frt.right && m_cf.SelEnd != m_cf.pLine[r].endoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINERIGHT, 0L);
			bInstTimer=TRUE;
		}
		if (point.x<m_cf.frt.left && m_cf.SelEnd != m_cf.pLine[r].begoff) {
			SendMessage(m_hWnd, WM_HSCROLL, SB_LINELEFT, 0L);
			bInstTimer=TRUE;
		}
	}
	if (bInstTimer==TRUE) {
		SetTimer(m_hWnd, 1, 100, NULL);
	} else {
		KillTimer(m_hWnd, 1);
	}
	return 1;
}

BOOL DETextCtrl::OnMouseWheel(UINT nFlags, short zDelta,POINT point)
{
	// Mouse wheel event.  zDelta is in multiples of 120.
	// Divide by 40 so each click is 3 lines.  I know some
	// drivers let you set the ammount of scroll, but I
	// don't know how to retrieve this or if they just
	// adjust the zDelta you get here.
	//If an application processes this message, it should return zero. 
	UINT Lines;
	int Unit;
	int nScroll=0;
	int Value;
	LOGFONT tFont;
	BOOL bShift, bControl;
	int action;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&Lines,0);
	Unit=WHEEL_DELTA/Lines;
	m_cf.SumDelta += zDelta;
	while (abs(m_cf.SumDelta) >= Unit) {
		if (m_cf.SumDelta > 0) {
			nScroll--;
			m_cf.SumDelta-=Unit;
		} else {
			nScroll++;
			m_cf.SumDelta+=Unit;
		}
	}

	// 컨트롤 키와 쉬프트키의 상태로부터 동작을 결정한다.
	if (bControl) {
		if (bShift) {
			action=m_pEF->nCtrlShiftWheel;
		} else {
			action=m_pEF->nCtrlWheel;
		}
	} else {
		if (bShift) {
			action=m_pEF->nShiftWheel;
		} else {
			action=m_pEF->nWheel;
		}
	}

	if (action==1) {
		Scroll(nScroll);
	} else {
		while ((UINT)abs(nScroll) >= Lines) {
			switch (action) {
			case 0:
				break;
			case 2:
				if (nScroll > 0) {
					Scroll(1);
				} else {
					Scroll(-1);
				}
				break;
			case 3:
				if (nScroll > 0) {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
				} else {
					SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
				}
				break;
			case 4:
				if (nScroll > 0) {
					Scroll(m_cf.Fheight/m_cf.LineHeight/2);
				} else {
					Scroll(-m_cf.Fheight/m_cf.LineHeight/2);
				}
				break;
			case 5:
				Value=GetLineRatio();
				if (nScroll > 0) {
					Value=max(Value-10,100);
				} else {
					Value=min(Value+10,1000);
				}
				SetLineRatio(Value);
				break;
			case 6:
				GetFont(&tFont);
				if (tFont.lfHeight != 0) {
					if (nScroll > 0) {
						tFont.lfHeight=max(tFont.lfHeight-3,12);
					} else {
						tFont.lfHeight=min(tFont.lfHeight+3,128);
					}
					SetFont(&tFont);
				}
				break;
			case 7:
				if (nScroll > 0) {
					if (m_pEF->CanUndo()) {
						m_pEF->Undo();
					}
				} else {
					if (m_pEF->CanRedo()) {
						m_pEF->Redo();
					}
				}
				break;
			}
			if (nScroll > 0) {
				nScroll -= Lines;
			} else {
				nScroll += Lines;
			}
		}
	}
	return FALSE;
}

BOOL DETextCtrl::OnContextMenu(HWND hFocus,POINT point)
{
	HMENU hPopup;
	POINT pt;

	hPopup=CreatePopupMenu();
	AppendMenu(hPopup,MF_STRING,IDM_AE_CUT,"잘라내기(&T)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_COPY,"복사(&C)");
	if (m_cf.ViewMode == HEXA_VIEW) {
		AppendMenu(hPopup,MF_STRING,IDM_AE_COPYDUMP,"덤프복사(&D)");
	}
	AppendMenu(hPopup,MF_STRING,IDM_AE_PASTE,"붙여넣기(&P)");
	AppendMenu(hPopup,MF_STRING,IDM_AE_SELALL,"모두선택(&A)");
	SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+4,(WPARAM)hPopup,0);

	if (IsClipboardFormatAvailable(CF_TEXT)==FALSE) {
		EnableMenuItem(hPopup, IDM_AE_PASTE, MF_BYCOMMAND | MF_GRAYED);
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		EnableMenuItem(hPopup, IDM_AE_CUT, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hPopup, IDM_AE_COPY, MF_BYCOMMAND | MF_GRAYED);
	}

	if (point.x==65535) {
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		point.x=pt.x;
		point.y=pt.y;
	}
	TrackPopupMenu(hPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,(short)point.x,(short)point.y,0,m_hWnd,NULL);
	DestroyMenu(hPopup);
	return 1;
}

BOOL DETextCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	TCHAR szChar[256];
	int i;
	BOOL bPrevSel;
	TCHAR szCom[256];

	if (nChar == 1) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		return 1;
	}
	if (nChar == 3) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		return 1;
	}
	if (nChar == 22) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		return 1;
	}
	if (nChar == 24) {
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
		return 1;
	}

	if (nChar == 25) {
		if (m_pEF->CanRedo())
			m_pEF->Redo();
		return 1;
	}
	if (nChar == 26) {
		if (m_pEF->CanUndo())
			m_pEF->Undo();
		return 1;
	}

	if ((nChar < ' ' && nChar != '\r' && nChar != '\t') || nChar==127)
		return 1;
	
	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 1;

	if (nChar == '\r') {
		szChar[0]='\r';
		szChar[1]='\n';
		szChar[2]=0;
	} else {
		szChar[0]=nChar;
		szChar[1]=0;
	}

	if (nChar == '\r') {
		lstrcpy(szCom,"insert \"\\n\"");
	} else if (nChar == '\t') {
		lstrcpy(szCom,"insert \"\\t\"");
	} else if (nChar == '\"') {
		lstrcpy(szCom,"insert \"\\\"\"");
	} else if (nChar == '\\') {
		lstrcpy(szCom,"insert \"\\\\\"");
	} else {
		wsprintf(szCom,"insert \"%s\"",szChar);
	}
	m_cmdH.pushCmd(szCom);
	ProcessCursorInEditing();

	if (nChar=='\t') {
		if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
			for (i=0;i<m_cf.TabWidth;i++) {
				szChar[i]=' ';
			}
			szChar[i]=0;
		}
		if (m_pEF->TestEditStyle(AES_BLOCKINDENTWITHTAB) && m_cf.SelStart != m_cf.SelEnd) {
			BlockIndent((GetKeyState(VK_SHIFT) & 0x8000) != 0);
			return 1;
		}
	}

	InputExtraSpace(m_cf.off);
	
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();
	for (i=0;i<(int)nRepCnt;i++) {
		if (m_cf.bOvr && bPrevSel==FALSE && nChar!='\r') {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}
	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));

	if (m_pEF->TestEditStyle(AES_AUTOINDENT)) {
		ProcessIndent(nChar);
	}

	SetCaret();
	TestAutoClip(nChar);
	return 1;
}

BOOL DETextCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 1;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy = !bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd && !bShift) {
		if (nChar==VK_LEFT || nChar==VK_RIGHT || nChar==VK_UP || nChar==VK_DOWN ||
			nChar==VK_PRIOR || nChar==VK_NEXT || nChar==VK_HOME || nChar==VK_END) {
			ClearSelection();
			m_cf.ExtraX=0;
			m_cf.SelExtraX=0;
		}
	}

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt++;
	}
	m_cf.bFindSelect=FALSE;

	if (nChar>='0' && nChar<='9' && bControl) {
		if (bShift) {
			ToggleBookmark(-1,nChar-'0');
		} else {
			GotoBookmark(nChar-'0');
		}
	}

	ProcessKey(nChar,bControl,bShift);

	if (bShift && !m_cf.bColumnMode) {
		m_cf.ignoreVirt--;
	}
	if (bShift && m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		m_cf.SelExtraX=m_cf.ExtraX;
	}
	return 1;
}

BOOL DETextCtrl::OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	BOOL bShift, bControl;
	BOOL bCopy = 0;

	bShift=((GetKeyState(VK_SHIFT) & 0x8000) != 0); 
	bControl=((GetKeyState(VK_CONTROL) & 0x8000) != 0);

	if (m_cf.bDragSel) {
		if (nChar == VK_CONTROL) {
			if (m_pEF->TestEditStyle(AES_SWAPDRAGBUTTON)) {
				bCopy=!bCopy;
			}
			if (bCopy) {
				SetCursor(DEEditCtrl::hCCopy);
			} else {
				SetCursor(DEEditCtrl::hCMove);
			}
		}
		return 1;
	}
	return 1;
}

BOOL DETextCtrl::OnHScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int xInc;
	SCROLLINFO si;
	int CharsPerPage;//krkim bugfix endless scroll

	if (!IsWindowEnabled(m_sbHorz)) {
		return 0;
	}
	CharsPerPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;
	xInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		xInc=-m_cf.FontHeight;
		break;
	case SB_LINEDOWN:
		xInc=m_cf.FontHeight;
		break;
	case SB_PAGEUP:
		xInc=-CharsPerPage;
		break;
	case SB_PAGEDOWN:
		xInc=CharsPerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbHorz,SB_CTL,&si);
		xInc=si.nTrackPos-m_cf.xPos;
		break;
	default:
		break;
	}

	xInc=max(-m_cf.xPos, min(xInc, m_cf.xMax-m_cf.xPos - CharsPerPage));
	//xInc=xInc-(xInc % m_cf.FontHeight);
	m_cf.xPos=m_cf.xPos+xInc;

	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, -xInc, 0, &m_cf.frt, &m_cf.frt);
	}
	SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
	ManageCaret();
	return KFCWnd::OnHScroll(nSBCode,nPos,hWndBar);
}

BOOL DETextCtrl::OnVScroll(UINT nSBCode,UINT nPos,HWND hWndBar)
{
	int yInc;
	SCROLLINFO si;
	int LinePerPage;
	RECT srt;

	if (!IsWindowEnabled(m_sbVert)) {
		return 0;
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=0;
	switch (nSBCode) {
	case SB_LINEUP:
		yInc=-m_cf.LineHeight;
		break;
	case SB_LINEDOWN:
		yInc=m_cf.LineHeight;
		break;
	case SB_PAGEUP:
		yInc=-LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc=LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize=sizeof(SCROLLINFO);
		si.fMask=SIF_TRACKPOS;
		GetScrollInfo(m_sbVert,SB_CTL,&si);
		yInc=si.nTrackPos-m_cf.yPos;
		break;
	default:
		break;
	}

	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	// 포맷팅 영역과 마진 영역만 스크롤한다.
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt,&srt);
	}
	SetScrollPos(m_sbVert, SB_CTL,m_cf.yPos, TRUE);
	ManageCaret();
	return KFCWnd::OnVScroll(nSBCode,nPos,hWndBar);
}

//it is called when a dialog box or message box is displayed.This gives we the opportunity to cancel modes such as mouse capture.
void DETextCtrl::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

// IME >>
LRESULT DETextCtrl::OnIMEStartComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	//return KFCWnd::OnIMEStartComposition(wParam,lParam);//디폴트타기
	return 1L;//ignore default process
}

LRESULT DETextCtrl::OnIMEEndComposition(WPARAM wParam,LPARAM lParam)
{
	BOOL bIMEComposition = TRUE;
	return KFCWnd::OnIMEEndComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMESetContext(WPARAM wParam,LPARAM lParam)
{
	//LONG lReturn;
	//다른세션창 전환후 원세션 복귀시 한/전 IME상태가 새롭게 변경이 된것을
	//내 세션의 IME상태에 맞게 재조정한다.
	//제목줄을 클릭하면 안되던현상.마우스기능을 호스트커서로 이동기능으로하고
	//Edit창을 클릭하면 dll의 chkKeyMode()를 타기때문에 자동변환이 되었으나,
	//제목줄을 클릭하거나 tabbar를 클릭하거나 마우스기능을 기본동작으로 한상태로
	//창을 전환하면 이전세션창의 ime상태를 가지고 있어서 이를 다시 내세션에 맞게 복귀하게함.
	//2003.06.13 krkim
	BOOL bActive = (BOOL)wParam;//윈도우가 활성화시 TRUE
	lParam = lParam & ~ISC_SHOWUICOMPOSITIONWINDOW; //조합상태를 IMECOMP창이아닌 내프로그램에출력.
	//lParam = lParam & ~ISC_SHOWUIALLCANDIDATEWINDOW;//이것을 clear하면 CANDIDATE WINDOW가 안뜬다.(한자창)

	int flag;
	HWND hwndIME = ImmGetDefaultIMEWnd(m_hWnd);
	flag = ImmIsUIMessage(hwndIME,WM_IME_SETCONTEXT, wParam, lParam);
	//lReturn = HandlerDefaultEditWindowProc(m_hWnd,message, wParam, lParam);
	return KFCWnd::OnIMESetContext(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEComposition(WPARAM wParam, LPARAM lParam) /*called when doing composite or complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;
	wsprintf(szmsg,"OnIMEComposition:chDBCS=[%s]%04X,flags =%04x\n",szDBCS,chDBCS,fFlags);
	OutputDebugString(szmsg);
	//Before processing WM_IME_CHAR ,bug after DBCS input and DBCS space or numeric.
	if(fFlags & GCS_RESULTSTR){//conform DBCS code
		//result ? no send here ,instead send in WM_IME_CHAR
		//WM_IME_CHAR is always RESULTSTRING with DBCS space or numeric and COMPOSITION CHAR.
	}
	//COMMENT 2003 05 09
	if(chDBCS == 0x0000)//FOR DELETE HANGUL DBCS Code ,,send once time 0x00
	{
		//입력조합중 백스페이스등으로 삭제했을 경우.
	}
#endif
	HIMC hImc;
	TCHAR *szComp;
	int len;
	BOOL bPrevSel;
	BOOL bNewIns=TRUE;

	if (m_pEF->bReadOnly || m_cf.bCapture)
		return 0;

	InputExtraSpace(m_cf.off);
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
		m_cf.bPrevCompoGroup=TRUE;
	}
	bPrevSel=DeleteSelection();
	hImc=ImmGetContext(m_hWnd);
	if (lParam & GCS_COMPSTR) {
		ProcessCursorInEditing();
		len=ImmGetCompositionString(hImc,GCS_COMPSTR,NULL,0);
		szComp=(TCHAR *)malloc(len+1);
		ImmGetCompositionString(hImc,GCS_COMPSTR,szComp,len);
		szComp[len]=0;
		if (m_cf.bComp && len!=0) {
			m_pEF->buf[m_cf.off-2]=szComp[0];
			m_pEF->buf[m_cf.off-1]=szComp[1];
			m_pEF->UpdateViews(this,m_cf.off-2,0);
		} else {
			if (m_cf.bComp) {
				m_cf.off-=2;
				Delete(m_cf.off,2,FALSE);
				bNewIns=FALSE;
			}
			if (len == 0) {
				m_cf.bComp=FALSE;
			} else {
				m_cf.bComp=TRUE;
			}

			if (m_cf.bOvr && bNewIns && bPrevSel==FALSE) {
				if (m_pEF->IsDBCS(m_cf.off)) {
					if (!m_pEF->IsEnterCode(m_cf.off)) {
						Delete(m_cf.off,2);
					}
				} else {
					Delete(m_cf.off,1);
				}
			}
			Insert(m_cf.off,szComp,lstrlen(szComp),FALSE);
			m_cf.off+=len;
		}

		ImmReleaseContext(m_hWnd,hImc);
		free(szComp);
		Invalidate(m_pEF->FindParaStart(m_cf.off-len));
		SetCaret();
	}

	return KFCWnd::OnIMEComposition(wParam,lParam);//디폴트타기
}

LRESULT DETextCtrl::OnIMEChar(WPARAM wParam, LPARAM lParam)  /*called when complete DBCS */
{
	//example code ------------------------------------------------------
#if 0
	BOOL bAlphaNumeric = FALSE;

	char szDBCS[3]={0,};
	WORD chDBCS = (WORD)wParam;
	int fFlags = (BOOL) lParam;
	szDBCS[0] = (chDBCS >> 8) & 0XFF;
	szDBCS[1] = (chDBCS ) & 0XFF;

	if((chDBCS >= 0xA3A1 && chDBCS <= 0xA3C0) || chDBCS == 0xA1A1)
	{
		bAlphaNumeric = TRUE;
	}

	byCtrl = BYC_NORMAL;	

	UINT wMode = InvokeIMECommand(0,(LPARAM)IME_COMMAND_GETCONVERSIONSTATUS);
	int fullmode = 0;
	if(wMode & IME_CMODE_FULLSHAPE) //전각모드
		fullmode = 1;

	wsprintf(szmsg,"WM_IME_CHAR=%xh(%d) wParam = [%s]%Xh lParam =%Xh,Full Shape Mode = %d\n",message,message,szDBCS,wParam,lParam,fullmode);
	OutputDebugString(szmsg);
	if(fullmode == 0)//반자모드로 전환된상태인데 전자가 이미 들어온경우
	{
		BOOL bControlAlphaNumeric = true;
		if(bAlphaNumeric && bControlAlphaNumeric) /*반자모드에서 전자숫자/기호 입력을 반자로변환 ?*/
		{
			char chSingle;
			chSingle = 0x21 + (chDBCS - 0xA3A1);
			if(chDBCS == 0xA1A1)
				chSingle = 0x20;
			TCHAR chars[3];
			chars[0] = chSingle;
			//PutMBCS(chars,false,true);
			PutChar(chSingle,false,false);
			break;
		}
	}
	if(szDBCS[0] == 0x00 || !IsDBCSLeadByte(szDBCS[0])){
		PutChar(szDBCS[1],false,false);
		break;
	}
	PutChar(szDBCS[0],true,false);
	PutChar(szDBCS[1],true,true);
	//PutMBCS(szDBCS,true,true);
#endif
	TCHAR szChar[3];
	TCHAR szCom[256];

	if (IsDBCSLeadByte((BYTE)(wParam >> 8))) {
		szChar[0]=HIBYTE(LOWORD(wParam));
		szChar[1]=LOBYTE(LOWORD(wParam));
		szChar[2]=0;
	} else {
		szChar[0]=(BYTE)wParam;
		szChar[1]=0;
	}

	if (m_cf.bComp) {
		m_pEF->URInsert(m_cf.off-lstrlen(szChar),szChar,lstrlen(szChar));
		m_pEF->buf[m_cf.off-2]=szChar[0];
		m_pEF->buf[m_cf.off-1]=szChar[1];
		if (m_cf.bPrevCompoGroup) {
			m_pEF->EndUndoGroup();
			m_cf.bPrevCompoGroup=FALSE;
		}
	} else {
		if (m_cf.bOvr) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				if (!m_pEF->IsEnterCode(m_cf.off)) {
					Delete(m_cf.off,2);
				}
			} else {
				Delete(m_cf.off,1);
			}
		}
		Insert(m_cf.off,szChar,lstrlen(szChar));
		m_cf.off+=lstrlen(szChar);
	}

	wsprintf(szCom,"insert \"%s\"",szChar);
	m_cmdH.pushCmd(szCom);

	m_cf.bComp=FALSE;
	Invalidate(m_pEF->FindParaStart(m_cf.off-lstrlen(szChar)));
	SetCaret();
	TestAutoClip(wParam);

	return 1L;//0L = through default window procedure,1L = ignore,디폴트 타지않게 한다
}

// << IME

///////////////////////////////////////////////////////////////////////////////////
// 일반 함수들

int DETextCtrl::GetCharWidth(TCHAR *ch, int len)
{
	SIZE sz;
	HDC hdc;
	HFONT hFont, hOldFont=NULL;
	int code;
	int idx;

	if (len == 1){
		idx = *(BYTE *)ch;
		if (idx == ' ') {
			return m_cf.SpaceWidth;
		} else {
			return m_cf.arChWidth[idx]*m_pEF->CharExtra/100;
		}
	} else {
		code=*(BYTE *)ch << 8 | *((BYTE *)ch+1);
		if (code == 0x0d0a) {
			return 0;
		}
		if (m_cf.arDBCSWidth[code-0x8000]==0xff) {
			hdc=GetDC(m_hWnd);
			if (m_cf.logfont.lfHeight != 0) {
				if (m_pEF->CharRatio != 100) {
					m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
				}
				hFont=CreateFontIndirect(&m_cf.logfont);
				hOldFont=(HFONT)SelectObject(hdc,hFont);
			}
			GetTextExtentPoint32(hdc,ch,2,&sz);
			if (hOldFont) {
				DeleteObject(SelectObject(hdc,hOldFont));
			}
			ReleaseDC(m_hWnd,hdc);
			m_cf.arDBCSWidth[code-0x8000]=(BYTE)sz.cx;
		}
		return m_cf.arDBCSWidth[code-0x8000]*m_pEF->CharExtra/100;
	}
}

void DETextCtrl::SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)
{
	int toff;
	int caretwidth;
	int x,y;
	int ty;
	BOOL bScroll=FALSE;
	POINT OldPos;
	RECT InvRt;
	RECT crt;

	GetCaretPos(&OldPos);

	if (m_cf.bComp) {
		toff=m_cf.off-2;
		caretwidth=GetCharWidth(m_pEF->buf+toff,2);
	} else {
		toff=m_cf.off;
		caretwidth=m_pEF->CaretWidth; 
	}

	if (m_cf.bOvr) {
		if (m_pEF->IsDBCS(toff)) {
			if (m_pEF->IsEnterCode(toff)) {
				caretwidth=m_cf.SpaceWidth;
			} else {
				caretwidth=GetCharWidth(m_pEF->buf+toff,2);
			}
		} else {
			caretwidth=GetCharWidth(m_pEF->buf+toff,1);
		}
	}
	if (GetFocus()==m_hWnd) {
		CreateCaret(m_hWnd,NULL,caretwidth,m_cf.FontHeight);
		ShowCaret(m_hWnd);
	}

	GetXYFromOff(toff,x,y);
	GetClientRect(m_hWnd,&crt);
	if (bScrollToCaret && crt.right) {
		m_pEF->SendNotify(AEN_MOVE);
		if (m_cf.nWrap==0) {
			if ((x+caretwidth > m_cf.xPos+m_cf.frt.right) || (x < m_cf.xPos+m_cf.frt.left)) {
				// 순수 문서 좌표에서 폭의 절반을 뺀 위치를 새로 정함
				m_cf.xPos=max(0,PureX(x)-(m_cf.frt.right-m_cf.frt.left)/2);
				bScroll=TRUE;
			}
		}

		// 순수 문서상의 좌표가 m_cf.yPos보다 더 작으면 그 줄로 스크롤 위치를 조정한다
		if (PureY(y) < m_cf.yPos) {
			m_cf.yPos=PureY(y);
			bScroll=TRUE;
		}

		if (y+m_cf.FontHeight > m_cf.yPos+m_cf.frt.bottom) {
			// ty=화면 제일 아래쪽의 보이는 줄의 화면상의 좌표. 줄간 영역은 제외. 배수 조정
			ty=(m_cf.frt.bottom-m_cf.frt.top-m_cf.FontHeight)/m_cf.LineHeight*m_cf.LineHeight;
			// 스크롤 위치 = 순서 문서상의 좌표에서 제일 아래 줄 좌표.(제일아래에서 특정줄 만큼 올리려면 -(m_cf.FontHeight * 줄수)
			m_cf.yPos=PureY(y)-ty;
			bScroll=TRUE;
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다.
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(m_cf.off == m_pEF->doclen && !bScroll){
			if(m_cf.yPos + m_cf.yPage < m_cf.yMax){
				m_cf.yPos = max(m_cf.yPos,min(m_cf.yPos + m_cf.LineHeight,m_cf.yMax - m_cf.yPage));
				bScroll = TRUE;
			}
		}
#endif
		if (bScroll == TRUE) {
			if (IsWindowEnabled(m_sbHorz)) {
				SetScrollPos(m_sbHorz, SB_CTL, m_cf.xPos, TRUE);
			}
			if (IsWindowEnabled(m_sbVert)) {
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			}
			Invalidate(-1);
		}
	}

	if (GetFocus()==m_hWnd) {
		SetCaretPos(x-m_cf.xPos,y-m_cf.yPos+GetCharYPos());
	}
	if (bUpdatePrevX) {
		m_cf.PrevX=x;
	}
	if (m_pEF->nShowCurLine != 0 && OldPos.y != y-m_cf.yPos) {
		InvRt.left=0;
		InvRt.right=m_cf.frt.right;
		InvRt.top=min(OldPos.y,y-m_cf.yPos)/m_cf.LineHeight*m_cf.LineHeight;
		InvRt.bottom=max(OldPos.y,y-m_cf.yPos)+m_cf.LineHeight;
		InvalidateRect(m_hWnd,&InvRt,FALSE);
	}
}

void DETextCtrl::Insert(int nPos, TCHAR *str, int len, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int r,c;
	int nowPara;
	TCHAR *p=str;

	if (m_pEF->bReadOnly)
		return;

	m_pEF->Insert(nPos,str,len,bRec);

	m_cf.bLineEnd=FALSE;
	UpdateParseInfo(nPos,len);
	UpdateLineInfo(nPos,len);
	UpdateScrollInfo();

	for (i=0;i<len;i++) {
		if (m_pEF->IsEnterCode(str,len,p))
			nCrLf++;
		p++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,r,c);
		nowPara=m_cf.pLine[r].nPara;
		if (c != 0) {
			nowPara++;
		}

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= nowPara) {
				m_cf.arMark[i]+=nCrLf;
			}
		}
	}
	m_pEF->UpdateViews(this,nPos,len);
}

void DETextCtrl::Delete(int nPos, int nCount, BOOL bRec/*=TRUE*/)
{
	int nCrLf=0,i;
	int sr,sc,er,ec;
	int sPara,ePara;
	TCHAR *p=m_pEF->buf+nPos;

	if (m_pEF->bReadOnly)
		return;

	if (nCount == 0) return;
	if (m_pEF->doclen < nPos+nCount) return;
	
	for (i=0;i<nCount;i++) {
		if (m_pEF->IsEnterCode(p+i))
			nCrLf++;
	}

	if (nCrLf) {
		GetRCFromOff(nPos,sr,sc);
		sPara=m_cf.pLine[sr].nPara;
		GetRCFromOff(nPos+nCount,er,ec);
		ePara=m_cf.pLine[er].nPara;

		for (i=0;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] >= sPara && m_cf.arMark[i] < ePara) {
				m_cf.arMark[i]=-1;
			}
			if (m_cf.arMark[i] >= ePara) {
				m_cf.arMark[i]-=nCrLf;
			}
		}
	}

	m_pEF->Delete(nPos,nCount,bRec);
	UpdateParseInfo(nPos,-nCount);
	UpdateLineInfo(nPos,-nCount);
	UpdateScrollInfo();
	m_pEF->UpdateViews(this,nPos,-nCount);
}

//레이아웃 설정에 따라 화면상의 줄번호에 해당하는 버퍼 위치를 구한다.
void DETextCtrl::GetLine(int Line, int &s, int &e)
{
	TCHAR *p, *Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	int Right;

	if (m_cf.RightWrap == 0) {
		Right=m_cf.frt.right-2;
	} else {
		Right=m_cf.frt.left+m_cf.RightWrap*m_cf.FontWidth;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+m_cf.pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (m_cf.nWrap == 0 && m_cf.RightWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=m_cf.frt.left,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (m_cf.nWrap==2 || (m_cf.nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				acwidth+=GetCharWidth(p,len);
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > max(Right, m_cf.frt.left+m_cf.FontHeight*4)) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (m_cf.nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}

	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && p < m_pEF->buf+m_pEF->doclen && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

void DETextCtrl::GetRCFromOff(int nPos, int &r, int &c)
{
	int Upper,Lower;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	Lower=0;
	Upper=m_cf.TotalLine-1;
	for (;;) {
		r=(Upper+Lower)/2;

		if (nPos > m_cf.pLine[r].begoff && nPos < m_cf.pLine[r].endoff)
			break;

		if (nPos == m_cf.pLine[r].begoff) {
			if (m_cf.pLine[r].nLine != 0 && m_cf.bLineEnd==TRUE) {
				r--;//bugfix :: krkim < 0
				if(r < 0)
					r = 0;
			}
			break;
		}

		if (nPos == m_cf.pLine[r].endoff) {
			if (AeIsLineEnd(m_pEF->buf+m_cf.pLine[r].endoff) || m_cf.bLineEnd == TRUE) {
				break;
			}
		}

		if (m_cf.pLine[r].begoff > nPos) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}

	c=nPos-m_cf.pLine[r].begoff;
	if (m_cf.ExtraX > 0) {
		c+=m_cf.ExtraX;
	}
}

int DETextCtrl::GetOffFromRC(int r, int c)
{
	int len;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	len=m_cf.pLine[r].endoff-m_cf.pLine[r].begoff;
	if (IsVirtualPosable()) {
		m_cf.ExtraX=max(c-len,0);
	} else {
		m_cf.ExtraX=0;
	}
	return m_cf.pLine[r].begoff+min(c,len);
}

void DETextCtrl::GetXYFromOff(int nPos, int &x, int &y)
{
	int r,c;
	TCHAR *p;

	assert(nPos >= 0 && nPos <= m_pEF->doclen);
	GetRCFromOff(nPos, r, c);
	y=r*m_cf.LineHeight+m_cf.frt.top;

	x=m_cf.frt.left;
	for (p=m_pEF->buf+m_cf.pLine[r].begoff;p!=m_pEF->buf+nPos;) {
		assert(p < m_pEF->buf+nPos);
		if (*p == '\t') {
			x = DocX((PureX(x)/m_cf.TabSize+1)*m_cf.TabSize);
			p++;
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				x += GetCharWidth(p,2);
				p+=2;
			} else {
				x += GetCharWidth(p,1);
				p++;
			}
		}
	}
	if (m_cf.ExtraX > 0) {
		x += m_cf.SpaceWidth*m_cf.ExtraX;
	}
}

int DETextCtrl::GetRowCount()
{
	return m_cf.TotalLine;
}

void DETextCtrl::SetWrap(int aWrap)
{
	m_cf.nWrap=aWrap;//0= 자동개행 x,1 글자단위,1= 한글글자,영문단어,2=한글단어,영문단어
	if (m_cf.nWrap && m_cf.RightWrap==0) {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.xPos=0;
	} else {
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_ENABLE_BOTH);
	}

	Invalidate(-1);
	UpdateLineInfo();
	UpdateScrollInfo();
	SetCaret();
}

int DETextCtrl::GetXPosOnLine(int r,int DestX)
{
	TCHAR *p;
	int len, acwidth;

	assert(r >= 0 && r <= m_cf.TotalLine-1);
	if (DestX == m_cf.frt.left) {
		return m_cf.pLine[r].begoff;
	}
	for (p=m_pEF->buf+m_cf.pLine[r].begoff, acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(DestX-acwidth)/m_cf.SpaceWidth;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			acwidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			acwidth+=GetCharWidth(p,len);;
		}

		p+=len;
		
		if (acwidth >= DestX) {
			m_cf.ExtraX=0;
			break;
		}
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

void DETextCtrl::UpdateScrollInfo()
{
	SCROLLINFO si;
	int i, MaxLength;
	
	int nOddLine = max(2,m_cf.Fheight/m_cf.LineHeight/4); //화면의 1/4 에 해당하는 줄수만큼 여유분
	m_cf.yMax = (GetRowCount() + nOddLine ) * m_cf.LineHeight;

	si.cbSize=sizeof(SCROLLINFO);
	si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin=0;
	si.nMax=m_cf.yMax;
	si.nPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
#ifdef DE_USE_ADJUSTSCROLLPOS
	m_cf.yPage = si.nPage;
#endif
	if (si.nMax < (int)si.nPage) {
		m_cf.yPos=0;
		Invalidate(-1);
	}
	si.nPos=m_cf.yPos;
	SetScrollInfo(m_sbVert, SB_CTL, &si, TRUE);
	if (si.nPage >= (unsigned)si.nMax) {
		EnableWindow(m_sbVert,FALSE);
	}
	//else{
	//	EnableWindow(m_sbVert,TRUE);
	//}
	if (m_cf.nWrap == 0 || m_cf.RightWrap != 0) {
		for (i=0,MaxLength=0;;i++) {
			if (m_cf.pLine[i].begoff==-1) {
				break;
			}
			MaxLength=max(MaxLength,(m_cf.pLine[i].endoff-m_cf.pLine[i].begoff));
		}

		m_cf.xMax=int(MaxLength*m_cf.FontWidth*1.5);
		si.nMax=m_cf.xMax;
		si.nPage=(m_cf.Fwidth/m_cf.FontHeight)*m_cf.FontHeight;//m_cf.Fwidth;
		si.nPos=m_cf.xPos;
#ifdef DE_USE_ADJUSTSCROLLPOS
		m_cf.xPage = si.nPage;
#endif
		SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		if (si.nPage >= (unsigned)si.nMax) {
			EnableWindow(m_sbHorz,FALSE);
		}
	}
	else{
		//SCROLLINFO si;
		//int i, MaxLength;
		//si.cbSize=sizeof(SCROLLINFO);
		//si.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
		//si.nMin=0;
		//si.nMax=0;
		//si.nPage=0;
		//si.nPos=0;
		//SetScrollInfo(m_sbHorz, SB_CTL, &si, TRUE);
		//EnableWindow(m_sbHorz,FALSE);
	}
}

int DETextCtrl::DrawLine(HDC hdc, int Line) /*hdc는 1라인분에 대한 dc이다 */
{
	int x,y;
	int len;
	int nowoff;
	BOOL bInSel;
	COLORREF fore, back;
	int SelFirst, SelSecond;
	int r,c;
	BOOL bCurLine=FALSE;
	RECT lrt;
	HBRUSH hCurLine;
	int toff;
	int style;
	BOOL bFindTextBlock;
	BOOL bSelEnter=FALSE;

	assert(Line >= 0 && Line <= m_cf.TotalLine-1);
	if (m_cf.pLine[Line].begoff == -1)
		return 0;

	if (m_cf.bComp) {
		toff=m_cf.off-2;
	} else {
		toff=m_cf.off;
	}
	GetRCFromOff(toff,r,c);
	if (r==Line && (m_pEF->TestEditStyle(AES_HIDECURLINE)==FALSE || GetFocus()==m_hWnd)) {
		bCurLine=TRUE;
	}

	// 배경 비트맵 출력
	if (m_pEF->hBackBit) {
		DrawBackBit(hdc,Line);
	}

	y=GetCharYPos();
	if (bCurLine && (m_pEF->nShowCurLine == 3 || m_pEF->nShowCurLine == 4)) {
		if (m_pEF->SelBlockType==0) {
			SetRect(&lrt,m_cf.frt.left,y,m_cf.frt.right,y+m_cf.FontHeight);
		} else {
			SetRect(&lrt,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight);
		}
		hCurLine = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_CURLINE));
		FillRect(hdc,&lrt,hCurLine);
		DeleteObject(hCurLine);
	}

	if (m_cf.bColumnMode == FALSE) {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		GetSelInLine(Line,SelFirst,SelSecond);
	}

	x=m_cf.frt.left-m_cf.xPos;
	nowoff=m_cf.pLine[Line].begoff;
	for (;;) {
		for (len=0;;) {
			assert(nowoff+len <= m_cf.pLine[Line].endoff);
			if (nowoff+len == m_cf.pLine[Line].endoff || len >= 1024) {
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}
			if (m_pEF->buf[nowoff+len] == '\t') {
				if (len == 0)
					len=1;
				if (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) {
					bInSel=TRUE;
				} else {
					bInSel=FALSE;
				}
				break;
			}

			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelFirst) {
				bInSel=FALSE;
				break;
			}
			if (m_cf.SelStart != m_cf.SelEnd && len != 0 && nowoff+len == SelSecond) {
				bInSel=TRUE;
				break;
			}
			int nPara = m_cf.pLine[Line].nPara;

			bFindTextBlock = FALSE;
			if(m_cf.Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
				bFindTextBlock = TRUE;
			else if(m_cf.Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
				bFindTextBlock = TRUE;

			if(bFindTextBlock){
				bInSel = (m_cf.SelStart != m_cf.SelEnd && nowoff >= SelFirst && nowoff < SelSecond) ?  TRUE : FALSE;
				//찾았으면 브레이크
				if(len != 0)
					break;
			}
			len += (m_pEF->IsDBCS(nowoff+len)) ? 2 : 1;
		}
		LOGFONT lfseg;
		DETEXTSTYLE textStyle;
		int nPara = m_cf.pLine[Line].nPara;
		style = m_cf.Parser->GetSearchBlockStyle(nPara,nowoff);
		if(style < 0)
			style = m_cf.Parser->GetStyle(nPara,nowoff);
		m_cf.Parser->GetTextStyle(style,textStyle);

		if (bInSel && (GetFocus()==m_hWnd || m_pEF->HideSelType!=0 || m_cf.bFindSelect)) {
			if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
				DETEXTSTYLE seltextStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_SELTEXT,seltextStyle);
				fore = seltextStyle.fore;
				back = seltextStyle.back;

				if(fore == -1)
					fore = m_pEF->GetColorFore(STYLEINDEX_SELTEXT);
				if(back == -1)
					back = m_pEF->GetColorBack(STYLEINDEX_SELTEXT);
			} else {
				fore = RGB(0,0,0);
				back = RGB(192,192,192);
			}
		} else {
			if (len==0) {
				fore=-1;
				back=-1;
			} else {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				fore = textStyle.fore;
				back = textStyle.back;
			}

			if (fore==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					fore = m_pEF->GetColorFore(STYLEINDEX_SEARCH);
				else
					fore = m_pEF->GetColorFore(STYLEINDEX_NORMAL);

			}
			if (back==(DWORD)-1) {
				if(style == STYLEINDEX_SEARCH)
					back = m_pEF->GetColorBack(STYLEINDEX_SEARCH);
				else
					back = m_pEF->GetColorBack(STYLEINDEX_BKGND);
			} 
			if ((m_pEF->nShowCurLine==3 || m_pEF->nShowCurLine==4) && bCurLine) {
				if(style != STYLEINDEX_SEARCH){
					fore = m_pEF->GetColorFore(STYLEINDEX_CURLINE);
					back = m_pEF->GetColorBack(STYLEINDEX_CURLINE);
				}
			}
		}
		
		// 줄끝의 선택된 개행 코드가 있는지 조사한다.
		if (nowoff+len == m_cf.pLine[Line].endoff) {
			if (!m_pEF->TestEditStyle(AES_SHOWENTER) && m_pEF->IsEnterCode(m_cf.pLine[Line].endoff) && 
				m_cf.pLine[Line].endoff >= SelFirst && m_cf.pLine[Line].endoff < SelSecond) {
				bSelEnter=TRUE;
			}
		}
		
		lfseg = m_cf.logfont;
		lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
		lfseg.lfUnderline = textStyle.bUnderline;
		lfseg.lfItalic = textStyle.bItalic;
		
		HFONT hsegFont = NULL;
		HFONT hOldFont = NULL;
		
		if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
			hsegFont = CreateFontIndirect(&lfseg);
			hOldFont = (HFONT)SelectObject(hdc,hsegFont);
		}
		// 선택된 개행 코드가 있으면 x갱신
		DrawSegment(hdc,x,y,nowoff,len,
			(nowoff+len==m_cf.pLine[Line].endoff && !bSelEnter),fore,back);
		if(hsegFont){
			DeleteObject(hsegFont);
			SelectObject(hdc,hOldFont);
		}
		nowoff+=len;
		// 선택된 개행 코드 출력
		if (nowoff == m_cf.pLine[Line].endoff) {
			if (bSelEnter) {
				if (m_pEF->SelBlockType==0) {
					SetRect(&lrt,x,y,x+m_cf.SpaceWidth,y+m_cf.FontHeight);
				} else {
					SetRect(&lrt,x,0,x+m_cf.SpaceWidth,m_cf.LineHeight);
				}
				if (GetFocus()==m_hWnd || m_pEF->HideSelType==2 || m_cf.bFindSelect) {
					hCurLine=CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELTEXT));
				} else {
					hCurLine=CreateSolidBrush(RGB(192,192,192));
				}
				FillRect(hdc,&lrt,hCurLine);
				DeleteObject(hCurLine);
			}
			break;
		}
	}

	DrawLineSub(hdc,Line,bCurLine);
	return 1;
}

/*hdc는 1라인에 대한 dc이다.nLine에 상관없이 시작위치는 0,0 이다*/
void DETextCtrl::DrawLineSub(HDC hdc,int Line,BOOL bCurLine)
{
	HBRUSH hMarBrush;
	HPEN hMarPen,OldPen;
	RECT mrt;
	TCHAR szLine[10];
	UINT OldAlign;
	HFONT OldFont;
	int OldExtra;
	int Mark;
	HBRUSH hMark, OldBrush;
	RECT lrt;
	int r,c,len;
	POINT tri[]={{1,1},{1,0},{0,0},{1,1}};
	int vy;

	vy=GetCharYPos();
	// 박스 또는 밑줄로 현재행 표시하기
	if ((m_pEF->nShowCurLine==1 || m_pEF->nShowCurLine==2 || 
		m_pEF->nShowCurLine==4) && bCurLine) {
		if (m_pEF->nShowCurLine == 1 || m_pEF->nShowCurLine == 4) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&lrt,m_cf.frt.left-1,vy,m_cf.frt.right+1,vy+m_cf.FontHeight);
			} else {
				SetRect(&lrt,m_cf.frt.left-1,0,m_cf.frt.right+1,m_cf.LineHeight);
			}
		} else {
			SetRect(&lrt,m_cf.frt.left-1,vy+m_cf.FontHeight,m_cf.frt.right+1,vy+m_cf.FontHeight);
		}
		SetTextColor(hdc,RGB(0,0,0));
		SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
		DrawFocusRect(hdc,&lrt);
	}

	// 자동 개행열 출력
	if (m_cf.ViewMode==TEXT_VIEW && m_cf.ColMark != 0) {
		hMarPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,0,NULL);
		LineTo(hdc,m_cf.frt.left+m_cf.ColMark*m_cf.FontWidth-m_cf.xPos,m_cf.LineHeight);
		SelectObject(hdc,OldPen);
		DeletePen(hMarPen);
	}

	DETEXTSTYLE edgeStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_DOCEDGE,edgeStyle);
	COLORREF credge = (edgeStyle.back != -1) ? edgeStyle.back : m_pEF->GetColorBack(STYLEINDEX_DOCEDGE);

	// 왼쪽 안쪽 여백 그림
	if (m_pEF->InnerRect.left){
		hMarBrush=CreateSolidBrush(credge);
		SetRect(&mrt,m_cf.MarginWidth,0,m_cf.frt.left,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		DeleteObject(hMarBrush);
	}

	// 마진 출력
	if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
		DETEXTSTYLE marginStyle;
		m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marginStyle);
		COLORREF crmarback = (marginStyle.back != -1) ? marginStyle.back : m_pEF->GetColorBack(STYLEINDEX_MARGIN);
		COLORREF crmarpen = (marginStyle.fore != -1) ? marginStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);
		hMarBrush=CreateSolidBrush(crmarback);
		/* 1라인분의 dc이기때문에 nLine에 상관없이 dc 시작위치는 left,top 0 이다.
		   OnPaint에서 각라인의 dc를 메인 dc에 라인단위로 복사한다.
		 */
		SetRect(&mrt,0,0,m_cf.MarginWidth,m_cf.LineHeight);
		FillRect(hdc,&mrt,hMarBrush);
		hMarPen=CreatePen(PS_SOLID,1,crmarpen);
		OldPen=(HPEN)SelectObject(hdc,hMarPen);
		MoveToEx(hdc,m_cf.MarginWidth-1,0,NULL);
		LineTo(hdc,m_cf.MarginWidth-1,m_cf.LineHeight);

		SelectObject(hdc,OldPen);
		DeleteObject(hMarPen);
		DeleteObject(hMarBrush);

		// 줄 번호 출력
		if (m_pEF->TestEditStyle(AES_SHOWLINENUM) && (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine==0)) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				wsprintf(szLine,"%d",m_cf.pLine[Line].nPara+1);
			} else {
				wsprintf(szLine,"%d",Line+1);
			}
			OldAlign=SetTextAlign(hdc,TA_RIGHT);

			DETEXTSTYLE linenumStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_LINENUM,linenumStyle);
			COLORREF crback = (linenumStyle.back != -1) ? linenumStyle.back : m_pEF->GetColorBack(STYLEINDEX_LINENUM);
			COLORREF crfore = (linenumStyle.fore != -1) ? linenumStyle.fore : m_pEF->GetColorFore(STYLEINDEX_LINENUM);
			if(crback != -1)
				SetBkColor(hdc,crback);
			SetTextColor(hdc,crfore);
			OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
			OldExtra=SetTextCharacterExtra(hdc,-1);
			int tx=m_cf.MarginWidth-3,ty = (m_cf.FontHeight-10)/2+vy;
			TextOut(hdc,tx,ty,szLine,lstrlen(szLine));
			
			SetTextCharacterExtra(hdc,OldExtra);
			SelectObject(hdc,OldFont);
			SetTextAlign(hdc,OldAlign);
		}

		// 북마크 출력
		if (m_cf.ViewMode==HEXA_VIEW || m_cf.pLine[Line].nLine == 0) {
			if (m_cf.ViewMode==TEXT_VIEW) {
				Mark=FindBookmark(m_cf.pLine[Line].nPara);
			} else {
				Mark=FindBookmark(Line);
			}
			if (Mark != -1) {
				DETEXTSTYLE bmStyle;
				m_cf.Parser->GetTextStyle(STYLEINDEX_BOOKMARK,bmStyle);
				COLORREF crback = (bmStyle.back != -1) ? bmStyle.back : m_pEF->GetColorBack(STYLEINDEX_BOOKMARK);
				COLORREF crfore = (bmStyle.fore != -1) ? bmStyle.fore : m_pEF->GetColorFore(STYLEINDEX_BOOKMARK);

				hMark=CreateSolidBrush(crback);
				OldBrush=(HBRUSH)SelectObject(hdc,hMark);
				RoundRect(hdc,0,vy,10,vy+m_cf.FontHeight,2,2);
				DeleteObject(SelectObject(hdc,OldBrush));
				if (Mark >= 0 && Mark <= 9) {
					wsprintf(szLine,"%d",Mark);
					OldAlign=SetTextAlign(hdc,TA_LEFT);
					SetTextColor(hdc,crfore);
					OldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);

					TextOut(hdc,2,vy+2,szLine,lstrlen(szLine));

					SelectObject(hdc,OldFont);
					SetTextAlign(hdc,OldAlign);
				}
			}
		}

		// 마진에 현재행 표시
		if (m_pEF->nShowCurLine == 5 && bCurLine) {
			DETEXTSTYLE marStyle;
			m_cf.Parser->GetTextStyle(STYLEINDEX_MARGIN,marStyle);
			COLORREF crfore = (marStyle.fore != -1) ? marStyle.fore : m_pEF->GetColorFore(STYLEINDEX_MARGIN);//경계선으로 그림
			HBRUSH hMar = CreateSolidBrush(crfore);
			OldBrush=(HBRUSH)SelectObject(hdc,hMar);
			r=min(m_cf.FontHeight,m_cf.MarginWidth);
			tri[1].y=r-1-r % 2;
			tri[2].x=r/2;
			tri[2].y=r/2;
			len=m_cf.FontHeight/2-tri[2].y;
			if (len!=0 || vy!=0) {
				for (c=0;c<4;c++) {
					tri[c].y+=len+vy;
				}
			}
			Polygon(hdc,tri,4);
			DeleteObject(SelectObject(hdc,OldBrush));
		}
	}
}

void DETextCtrl::DrawSegment(HDC hdc, int &x, int y, int SegOff, int len, BOOL ignoreX,
	COLORREF fore, COLORREF back)
{
	int docx;
	int oldx;
	RECT rt;
	HBRUSH Brush;

	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	if (m_pEF->buf[SegOff] == '\t') {
		oldx=x;
		docx=x+m_cf.xPos;
		docx=DocX((PureX(docx)/m_cf.TabSize+1)*m_cf.TabSize);
		x=docx-m_cf.xPos;
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x+1,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x+1,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		if (m_pEF->TestEditStyle(AES_SHOWTAB)) {
			DisplayTab(hdc,oldx,x,y,back);
		}
	} else {
		SetTextColor(hdc,fore);
		oldx=x;
		if (m_pEF->TestEditStyle(AES_SHOWENTER) || ignoreX == FALSE || back != crbkg) {
			x+=MyGetTextExtent(m_pEF->buf+SegOff,len);
		}
		if (back != crbkg) {
			if (m_pEF->SelBlockType==0) {
				SetRect(&rt,oldx,y,x,y+m_cf.FontHeight);
			} else {
				SetRect(&rt,oldx,0,x,m_cf.LineHeight);
			}
			Brush=CreateSolidBrush(back);
			FillRect(hdc,&rt,Brush);
			DeleteObject(Brush);
		}
		AeTextOut(hdc,oldx,y,m_pEF->buf+SegOff,len);
		if (m_pEF->TestEditStyle(AES_SHOWSPACE)) {
			DisplaySpace(hdc,oldx,y,m_pEF->buf+SegOff,len);
		}
	}
	if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
		if (m_pEF->IsEnterCode(SegOff+len)) {
			if (SegOff+len >= min(m_cf.SelStart,m_cf.SelEnd) && SegOff+len < max(m_cf.SelStart,m_cf.SelEnd)) {
				DisplayEnter(hdc,x,y,back);
			} else {
				DisplayEnter(hdc,x,y,crbkg);
			}
		}
	}
}

int DETextCtrl::GetOffFromXY(int x, int y)
{
	int r,len;
	TCHAR *p;
	int chWidth;
	int acwidth;

	x=max(x,m_cf.frt.left);
	y=max(y,m_cf.frt.top);

	r=PureY(y)/m_cf.LineHeight;
	r=min(r,GetRowCount()-1);

	for (p=m_pEF->buf+m_cf.pLine[r].begoff,acwidth=m_cf.frt.left;;) {
		if (p-m_pEF->buf == m_cf.pLine[r].endoff) {
			if (IsVirtualPosable()) {
				m_cf.ExtraX=(x-acwidth)/m_cf.SpaceWidth;
			} else {
				m_cf.ExtraX=0;
			}
			break;
		}
		assert(p < m_pEF->buf+m_cf.pLine[r].endoff);

		if (*p == '\t') {
			len=1;
			chWidth=DocX((PureX(acwidth)/m_cf.TabSize+1)*m_cf.TabSize-acwidth);
		} else {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				len=2;
			} else {
				len=1;
			}
			chWidth=GetCharWidth(p,len);
		}

		acwidth += chWidth;
		if (acwidth-chWidth/2 >= x) {
			m_cf.ExtraX=0;
			break;
		}

		p+=len;
	}

	m_cf.bLineEnd=(p-m_pEF->buf==m_cf.pLine[r].endoff && !AeIsLineEnd(p));
	return p-m_pEF->buf;
}

BOOL DETextCtrl::IsDelimiter(int nPos)
{
	return (strchr(m_cf.Parser->GetInfo(1),m_pEF->buf[nPos]) || m_pEF->buf[nPos]==0);
}

int DETextCtrl::GetPrevWord(int nPos)
{
	if (nPos == 0)
		return nPos;

	for (nPos--;;nPos--) {
		if (IsDelimiter(nPos)==FALSE || nPos==0) {
			break;
		}
	}

	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if (nPos != 0)
		nPos++;
	return nPos;
}

int DETextCtrl::GetNextWord(int nPos)
{
	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}

	for (;;nPos++) {
		if (IsDelimiter(nPos)==FALSE || m_pEF->buf[nPos]==0) {
			break;
		}
	}
	return nPos;
}

void DETextCtrl::ClearSelection()
{
	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
		m_cf.SelStart=m_cf.SelEnd=0;
	}
}

void DETextCtrl::ExpandSelection(int Start, int End)
{
	int OldSelEnd;

	if (m_cf.SelStart==m_cf.SelEnd) {
		m_cf.SelStart=Start;
		m_cf.SelEnd=End;
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	} else {
		OldSelEnd=m_cf.SelEnd;
		m_cf.SelEnd=End;
		Invalidate(min(OldSelEnd,m_cf.SelEnd),max(OldSelEnd,m_cf.SelEnd));
	}
	if (m_cf.bColumnMode || m_pEF->SelBlockType==2) {
		Invalidate(min(m_cf.SelStart,m_cf.SelEnd),max(m_cf.SelStart,m_cf.SelEnd));
	}
}

BOOL DETextCtrl::DeleteSelection()
{
	int SelFirst, SelSecond;
	int idx,Acc,linelen;

	if (m_cf.SelStart != m_cf.SelEnd) {
		if (!m_cf.bColumnMode) {
			SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
			SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				m_pEF->StartUndoGroup(24);
			}
			Delete(SelFirst,SelSecond-SelFirst);
			m_cf.off=SelFirst;
			if (m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
				AdjustSpace(m_cf.off,FALSE);
				m_pEF->EndUndoGroup();
			}
		} else {
			MakeSelTable();
			m_pEF->StartUndoGroup(16);
			for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
				linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
				Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
				Acc+=linelen;
			}
			m_pEF->EndUndoGroup();
			m_cf.ExtraX=0;
			m_cf.off=m_cf.SelTable[0].begoff;
			FreeSelTable();
		}
		m_cf.SelStart=m_cf.SelEnd=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::PrepareCharWidth(HDC hdc)
{
	int i;
	TCHAR Char[3]={0,};
	SIZE sz;
	int hi,low;
	BOOL Const=FALSE;

	for (i=0;i<=255;i++) {
		Char[0]=i;
		GetTextExtentPoint32(hdc, Char, 1, &sz);
		m_cf.arChWidth[i]=(BYTE)sz.cx;
	}
	m_cf.SpaceWidth=m_cf.arChWidth[' ']*m_pEF->CharExtra*m_pEF->WordExtra/100/100;

	if (m_cf.arDBCSWidth) {
		free(m_cf.arDBCSWidth);
	}
	m_cf.arDBCSWidth=(BYTE *)malloc(0x8000);
	for (i=0;i<0x8000;i++) {
		m_cf.arDBCSWidth[i]=0xff;
	}

	for (hi=0xb000;hi<=0xc800;hi+=0x100) {
		for (low=0xa1;low<=0xfe;low++) {
			Char[0]=hi >> 8;
			Char[1]=low;
			if (Const==TRUE) {
				sz.cx=m_cf.arDBCSWidth[0xb0a1-0x8000];
			} else {
				GetTextExtentPoint32(hdc,Char,2,&sz);
			}
			m_cf.arDBCSWidth[hi+low-0x8000]=(BYTE)sz.cx;
			if (hi==0xb000 && low==0xfe) {
				for (i=0xb0a1,Const=TRUE;i<=0xb0fe;i++) {
					if (m_cf.arDBCSWidth[i-0x8000] != m_cf.arDBCSWidth[0xb0a1-0x8000]) {
						Const=FALSE;
					}
				}
			}
		}
	}
}

int DETextCtrl::MyGetTextExtent(TCHAR *text, int len)
{
	TCHAR *p=text;
	int acwidth;

	for (acwidth=0;p-text!=len;) {
		if (m_pEF->IsDBCS(p-m_pEF->buf)) {
			acwidth+=GetCharWidth(p,2);
			p+=2;
		} else {
			acwidth+=GetCharWidth(p,1);
			p++;
		}
	}
	return acwidth;
}

//검색결과 표시 정책:
/*
	키입력시,
	1)그대로 표시하는 방법 - UpdateLineInfo 시점에서 검색무효화,OnPaint에서 ParseLines 호출시 검색파싱
	2)표시내용 없애는 방법 - 문서변동시점에서 HideSearchText() 호출
*/
void DETextCtrl::HideSearchText()//검색취소,키입력이 발생하여 문서가 변경되면 무효화 해야 한다.
{
	if(m_cf.Parser->InvalidSearchBlock() > 0)
		Invalidate(-1);
}

//문서처음부터 nLineTo 까지 검색
int DETextCtrl::ShowSearchText(int nLineTo,DWORD dwFindFlag)
{
	int nLineToo = (nLineTo < 0 || nLineTo >= m_cf.TotalLine) ? m_cf.TotalLine - 1 : nLineTo;
	int nCount = m_cf.Parser->ParseSearchText(*this,nLineToo,dwFindFlag);
	Invalidate(-1);
	return nCount;
}

int DETextCtrl::GetSearchCount()
{
	return m_cf.Parser->m_nSearchCount;
}

//문단별로 구문분석을 한다.사실상 리사이징,폰트변경,마진등 문서외적인 요소의 변동에는 갱신하지 않아도 된다.
void DETextCtrl::UpdateParseInfo(int nPos/*=-1*/, int nChars/*=-1*/)
{
	int r,c;
	int nPara, nLine=0;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;

	if(nPos==-1){
		r=0;
		nPara=0;
	}else{
		ParaStart = m_pEF->FindParaStart(nPos);
		if(ParaStart == 0){
			r = 0;
			nPara = 0;
		} else {
			GetRCFromOff(ParaStart-2,r,c);
			nPara = m_cf.pLine[r].nPara+1;
			r++;
		}
	}
	//TODO::
	//이것도 엄밀히 하자면,nPos에서 nChars 만큼 가감변동된 것만큼 문단의 변화를 따져서 
	//해당 전후 문단만 해야함- 입력케이스에 따라 복잡하므로 생략한다.
	//즉,대략적으로 CRLF가 추가되면 문단을 삽입하고 해당문단과 바로위문단만 갱신 나머지는 그대로복사
	//CRLF가 삭제되면 다음문단을 갯수만큼 당겨서 복사해야 한다. 일반문자만 입력되면 해당 문단만 갱신하면 된다.
	//나중에 입력시 버벅대면 속도개선 차원에서 작업필요,
	//현재는 리사이징이나 폰트변경 등 문서외적인 변화시에 구문분석이 필요없으므로(문단단위로 하므로,라인단위로 하면 매번 해줘야한다)
	//이 함수를 별도로 빼서 문서변동시 (IME조합 OnIMEComposition,Insert,Delete)에서만 수행하게 한다
	//이렇게 되면 아래 함수에서 단순히 nPara부터 모조리 리셋만 하는게 아니라,위와같은 복사및 삽입후 해당 문단만 리셋 처리를 해주어야 한다.
	//전부리셋후 문서를 스크롤할때나 페인트시 다시 파싱하게 된다.전부 한번씩 갱신 될때까지.
	m_cf.Parser->InvalidTextBlock(nPara);
}

void DETextCtrl::UpdateLineInfo(int nPos/*=-1*/, int nCount/*=-1*/)
{
	int l,s,e;
	int nPara, nLine=0;
	int i;
	int ParaStart;
	int ps=-1,pe=-1,pp=0;
	int dPara;

	if (nPos==-1) {
		l=0;
		nPara=0;
	} else {
		ParaStart=m_pEF->FindParaStart(nPos);
		if (ParaStart == 0) {
			l=0;
			nPara=0;
		} else {
			GetRCFromOff(ParaStart-2,l,e);
			nPara=m_cf.pLine[l].nPara+1;
			l++;
		}
	}
	for (;;l++) {
		if (l >= m_cf.Linelen) {
			m_cf.Linelen += 1000;
			m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
			if (m_cf.pLine == NULL) {
			}
			for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
				m_cf.pLine[i].begoff=-1;
			}
		}

		GetLine(l,s,e);
		if (nPos != -1 && e > nPos && m_cf.pLine[l].begoff != -1) {
			if (m_cf.pLine[l].begoff+nCount == s && m_cf.pLine[l].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i].begoff==-1)
						break;
					m_cf.pLine[i].begoff+=nCount;
					m_cf.pLine[i].endoff+=nCount;
					m_cf.pLine[i].nPara+=dPara;
				}
				break;
			}

			if (ps+nCount == s && pe+nCount == e) {
				if (m_cf.TotalLine+1 >= m_cf.Linelen) {
					m_cf.Linelen += 1000;
					m_cf.pLine=(DELINEINFO *)realloc(m_cf.pLine,sizeof(DELINEINFO)*m_cf.Linelen);
					if (m_cf.pLine == NULL) {
					}
					for (i=m_cf.Linelen-1000;i<m_cf.Linelen;i++) {
						m_cf.pLine[i].begoff=-1;
					}
				}
				dPara=nPara-pp;
				m_cf.pLine[m_cf.TotalLine+1].begoff=-1;
				for (i=m_cf.TotalLine;i>=l;i--) {
					m_cf.pLine[i].begoff=m_cf.pLine[i-1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i-1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i-1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i-1].nLine;
				}
				m_cf.pLine[l].begoff=s;
				m_cf.pLine[l].endoff=e;
				m_cf.pLine[l].nPara=nPara;//소속된 문단인덱스
				m_cf.pLine[l].nLine=nLine;//문단내 화면상의 라인인덱스
				m_cf.TotalLine++;
				break;
			}
			
			if (m_cf.pLine[l+1].begoff+nCount == s && m_cf.pLine[l+1].endoff+nCount == e) {
				dPara=nPara-m_cf.pLine[l+1].nPara;
				for (i=l;;i++) {
					if (m_cf.pLine[i+1].begoff==-1) {
						m_cf.pLine[i].begoff=-1;
						break;
					}
					m_cf.pLine[i].begoff=m_cf.pLine[i+1].begoff+nCount;
					m_cf.pLine[i].endoff=m_cf.pLine[i+1].endoff+nCount;
					m_cf.pLine[i].nPara=m_cf.pLine[i+1].nPara+dPara;
					m_cf.pLine[i].nLine=m_cf.pLine[i+1].nLine;
				}
				m_cf.TotalLine--;
				break;
			}
		}

		ps=m_cf.pLine[l].begoff;
		pe=m_cf.pLine[l].endoff;
		pp=m_cf.pLine[l].nPara;

		m_cf.pLine[l].begoff=s;
		m_cf.pLine[l].endoff=e;
		m_cf.pLine[l].nPara=nPara;
		m_cf.pLine[l].nLine=nLine;
		if (s==-1) {
			m_cf.TotalLine=l;
			if (m_pEF->TestEditStyle(AES_SHOWMARGIN)) {
				int nNumLen,oldmargin = m_cf.MarginWidth;
				TCHAR szNum[32];
				nNumLen = sprintf(szNum,"%d",nPara);
				if(nNumLen < 4) nNumLen = 4; /*최소4*/
				if(nNumLen == 4  && m_cf.MarginWidth != MARGINWIDTH) /* 천,4자리 */
					m_cf.MarginWidth = MARGINWIDTH; /* 20 = 4 CHARS * LINENUMCHARWIDTH PIXEL*/
				else
					m_cf.MarginWidth = max(MARGINWIDTH,nNumLen * LINENUMCHARWIDTH);
				if(oldmargin != m_cf.MarginWidth){
					PostMessage(m_hWnd,WM_SIZE,0,0);
					Invalidate(-1);
				}
			}
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}
}

void DETextCtrl::Invalidate(int Pos1, int Pos2/*=-1*/)
{
	RECT rt;
	int x,y,y1,y2;

	if (Pos1 == -1) {
		InvalidateRect(m_hWnd,NULL,FALSE);
		return;
	}

	GetXYFromOff(Pos1,x,y);
	y1=y-m_cf.yPos;

	if (Pos2 == -1) {
		y2=m_cf.frt.bottom;
	} else {
		GetXYFromOff(Pos2,x,y);
		y2=y-m_cf.yPos+m_cf.LineHeight;
	}

	SetRect(&rt,0,y1,m_cf.frt.right,y2);
	InvalidateRect(m_hWnd,&rt,FALSE);
}

void DETextCtrl::ClearBookmark()
{
	int i;
	for (i=0;i<MAXBOOKMARK;i++) {
		m_cf.arMark[i]=-1;
	}
	Invalidate(-1);
}

void DETextCtrl::ToggleBookmark(int Para, int Mark)
{
	int r,c;
	int i;
	int state;
	TCHAR szCom[256];

	if (Para == -1) {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			Para=r;
		} else {
			Para=m_cf.pLine[r].nPara;
		}
	}
	
	if (Mark <= 9) {
		wsprintf(szCom,"setmark %d",Mark);
		m_cmdH.pushCmd(szCom);
		if (m_cf.arMark[Mark] == -1) {
			m_cf.arMark[Mark]=Para;
		} else {
			if (m_cf.arMark[Mark] == Para) {
				m_cf.arMark[Mark]=-1;
			} else {
				m_cf.arMark[Mark]=Para;
			}
		}
	} else {
		m_cmdH.pushCmd("setmark unname");
		state=FindBookmark(Para);
		if (state == -1) {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=-1;i++);
			if (i==MAXBOOKMARK) {
				return;
			}
			m_cf.arMark[i]=Para;
		} else {
			for (i=10;i<MAXBOOKMARK && m_cf.arMark[i]!=Para;i++);
			m_cf.arMark[i]=-1;
		}
	}

	Invalidate(-1);
}

void DETextCtrl::GotoBookmark(int Mark)
{
	int Para;
	int i;
	int r,c;
	int nowPara;
	int Min=1000000,Max=-1,Next=1000000,Prev=-1;
	TCHAR szCom[256];
	int OldyPos;

	if (Mark<=9) {
		wsprintf(szCom,"gomark %d",Mark);
		m_cmdH.pushCmd(szCom);
		Para=m_cf.arMark[Mark];
		if (Para == -1) {
			return;
		}
	} else {
		GetRCFromOff(m_cf.off,r,c);
		if (m_cf.ViewMode==HEXA_VIEW) {
			nowPara=r;
		} else {
			nowPara=m_cf.pLine[r].nPara;
		}
		for (i=10;i<MAXBOOKMARK;i++) {
			if (m_cf.arMark[i] == -1)
				continue;
			Min=min(m_cf.arMark[i],Min);
			Max=max(m_cf.arMark[i],Max);
			if (m_cf.arMark[i] > nowPara) {
				Next=min(m_cf.arMark[i],Next);
			}
			if (m_cf.arMark[i] < nowPara) {
				Prev=max(m_cf.arMark[i],Prev);
			}
		}

		if (Mark == 10) {
			m_cmdH.pushCmd("gomark next");
			if (Next == 1000000) {
				Para=Min;
				if (Para == 1000000) {
					return;
				}
			} else {
				Para=Next;
			}
		} else {
			m_cmdH.pushCmd("gomark prev");
			if (Prev == -1) {
				Para=Max;
				if (Para == -1) {
					return;
				}
			} else {
				Para=Prev;
			}
		}
	}

	OldyPos=m_cf.yPos;
	GotoLine(Para,0,(m_cf.ViewMode==HEXA_VIEW) ? 0:1);
	if (OldyPos!=m_cf.yPos) {
		ArrangeVerticalCenter(m_cf.off);
	}
}

void DETextCtrl::GotoLine(int Line, int Col/*=0*/, int Type/*=0*/)
{
	int tLine;
	int toff;
	ClearSelection();

	switch (Type) {
	case 0:
		if (m_cf.ViewMode==TEXT_VIEW) {
			tLine=min(Line,m_cf.TotalLine-1);
		} else {
			tLine=min(Line,GetRowCount()-1);
		}
		m_cf.off=GetOffFromRC(Line,Col);
		break;
	case 1:
		toff=GetOffFromPara(Line,Col);
		if (toff!=-1) {
			m_cf.off=toff;
		}
		break;
	}
	SetCaret();
}

int DETextCtrl::FindBookmark(int Para)
{
	int i;

	for (i=0;i<MAXBOOKMARK;i++) {
		if (m_cf.arMark[i] == Para) {
			return (i <= 9) ? i:100;
		}
	}
	return -1;
}

void DETextCtrl::DisplayTab(HDC hdc, int x1, int x2, int y,COLORREF back)
{
	static BYTE arTab[]={0,0,1,0,2,0,1,1,1,2,1,3,1,4,
		4,0,3,1,3,2,3,3,3,4,5,1,5,2,5,3,5,4,4,2,
		6,0,6,1,6,2,6,3,6,4,7,0,7,2,7,4,8,1,8,3};
	HPEN hPen,OldPen;
	int i;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowTabType()) {
	case 0:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight/2,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight/2+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight/2);
		break;
	case 1:
		MoveToEx(hdc,x1+1,y+m_cf.FontHeight*3/4,NULL);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x2-3,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x2-1,y+m_cf.FontHeight*3/4);
		for (i=0;i<sizeof(arTab)/sizeof(arTab[0]);i+=2) {
			SetPixel(hdc,arTab[i]+x1+2,y+arTab[i+1]+m_cf.FontHeight*3/4-6,crback);
		}
		break;
	}

	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplayEnter(HDC hdc, int x, int y,COLORREF back)
{
	HPEN hPen,OldPen;
	HBRUSH OldBrush;
	RECT rt,brt;
	int width;
	HBRUSH Brush;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	hPen=CreatePen(PS_SOLID,1,crback);
	OldPen=(HPEN)SelectObject(hdc,hPen);

	switch (m_pEF->GetShowEnterType()) {
	case 0:
		width=m_cf.SpaceWidth*2;
		break;
	case 1:
		width=m_cf.SpaceWidth*3;
		break;
	case 2:
		width=m_cf.SpaceWidth*3;
		break;
	}
	DETEXTSTYLE bkgStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_BKGND,bkgStyle);
	COLORREF crbkg = (bkgStyle.back != -1) ? bkgStyle.back : m_pEF->GetColorBack(STYLEINDEX_BKGND);//경계선으로 그림

	SetRect(&rt,x,y,x+width,y+m_cf.FontHeight);
	if (back != crbkg) {
		if (m_pEF->SelBlockType==0) {
			brt=rt;
		} else {
			SetRect(&brt,x,0,x+width,m_cf.LineHeight);
		}
		Brush=CreateSolidBrush(back);
		FillRect(hdc,&brt,Brush);
		DeleteObject(Brush);
	}

	if (m_pEF->GetShowEnterType() <= 1) {
		MoveToEx(hdc,x+width-2,y+m_cf.FontHeight/10,NULL);
		LineTo(hdc,x+width-2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4-2);
		LineTo(hdc,x+4,y+m_cf.FontHeight*3/4+2);
		LineTo(hdc,x+2,y+m_cf.FontHeight*3/4);
	} else {
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
		Rectangle(hdc,rt.left+1,rt.top+1,rt.right-1,rt.bottom-1);
		SelectObject(hdc,OldBrush);
		MoveToEx(hdc,x+width-4,y+m_cf.FontHeight/5,NULL);
		LineTo(hdc,x+width-4,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8-2);
		LineTo(hdc,x+5,y+m_cf.FontHeight*5/8+2);
		LineTo(hdc,x+3,y+m_cf.FontHeight*5/8);
	}
	SelectObject(hdc,OldPen);
	DeleteObject(hPen);
}

void DETextCtrl::DisplaySpace(HDC hdc, int x, int y, TCHAR *text, int len)
{
	int nPos;
	int nx=x;
	int width;
	HPEN hPen,OldPen;
	HBRUSH OldBrush;

	width = m_cf.SpaceWidth;

	DETEXTSTYLE escStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_ESCAPE,escStyle);
	COLORREF crback = (escStyle.back != -1) ? escStyle.back : m_pEF->GetColorBack(STYLEINDEX_ESCAPE);//경계선으로 그림

	if (m_pEF->GetShowSpaceType()!=0) {

		hPen=CreatePen(PS_SOLID,1,crback);
		OldPen=(HPEN)SelectObject(hdc,hPen);
		OldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(NULL_BRUSH));
	}
	for (nPos=0;nPos!=len;nPos++) {
		if (text[nPos] == 0x20) {
			switch (m_pEF->GetShowSpaceType()) {
			default:
			case 0:
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2,crback);
				SetPixel(hdc,nx+width/2,y+m_cf.FontHeight/2+1,crback);
				break;
			case 1:
				MoveToEx(hdc,nx,y+m_cf.FontHeight*3/4+1,NULL);
				LineTo(hdc,nx,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight-1);
				LineTo(hdc,nx+width-1,y+m_cf.FontHeight*3/4);
				break;
			case 2:
				Rectangle(hdc,nx,0,nx+width,y+m_cf.FontHeight);
				break;
			}
			nx+=width;
		} else {
			if (m_pEF->IsDBCS(text-m_pEF->buf+nPos)) {
				nx += GetCharWidth(text+nPos,2);
				nPos++;
			} else {
				nx += GetCharWidth(text+nPos,1);
			}
		}
	}
	if (m_pEF->GetShowSpaceType()!=0) {
		SelectObject(hdc,OldPen);
		DeleteObject(hPen);
		SelectObject(hdc,OldBrush);
	}
}

void DETextCtrl::GetNowWord(int nPos, int &s, int &e)
{
	for (;;nPos--) {
		if (IsDelimiter(nPos)==TRUE || nPos==0) {
			break;
		}
	}

	if ((nPos != 0 || IsDelimiter(nPos)) && 
		nPos != m_pEF->doclen && IsDelimiter(nPos+1)==FALSE) {
		nPos++;
	}
	s=nPos;

	for (;;nPos++) {
		if (IsDelimiter(nPos)==TRUE) {
			break;
		}
	}
	e=nPos;
}

BOOL DETextCtrl::IsInSelection(int x,int y)
{
	int toff;
	int r,c;
	int ss,se;
	int SelFirst, SelSecond;
	int x1,y1,x2,y2;
	RECT rt;
	POINT pt;
	BOOL bRet;
	int BkExtraX;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return FALSE;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);

	BkExtraX=m_cf.ExtraX;
	m_cf.ignoreVirt++;
	toff=GetOffFromXY(x,y);
	GetRCFromOff(toff,r,c);

	if (m_cf.bColumnMode) {
		GetSelInLine(r,ss,se);
	} else {
		if (SelFirst > m_cf.pLine[r].endoff || SelSecond <= m_cf.pLine[r].begoff) {
			bRet=FALSE;
			goto End;
		}

		if (SelFirst < m_cf.pLine[r].begoff) {
			ss=m_cf.pLine[r].begoff;
		} else {
			ss=SelFirst;
		}

		if (SelSecond > m_cf.pLine[r].endoff) {
			se=m_cf.pLine[r].endoff;
		} else {
			se=SelSecond;
		}
	}

	se=m_pEF->GetPrevOff(se);

	GetXYFromOff(ss,x1,y1);
	GetXYFromOff(se,x2,y2);
	if (m_pEF->IsDBCS(se)) {
		x2 += GetCharWidth(m_pEF->buf+se,2);
	} else {
		x2 += GetCharWidth(m_pEF->buf+se,1);
	}

	SetRect(&rt,x1,y1,x2,y1+m_cf.LineHeight);
	pt.x=x;
	pt.y=y;
	bRet=PtInRect(&rt,pt);

End:
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
	return bRet;
}

void DETextCtrl::CopyString(BOOL bCopy, int from, int &to, int len, BOOL bRec/*=TRUE*/)
{
	TCHAR *t;
	int orito=to;
	int BkExtraX;
	int ss,se;
	int nIns;

	BkExtraX=m_cf.ExtraX;
	if (InputExtraSpace(to)) {
		if (from > to-BkExtraX) {
			from+=BkExtraX;
		}
	}

	t=(TCHAR *)malloc(len);
	memcpy(t,m_pEF->buf+from,len);
	// 스마트 공백이고 기록 모드일 때만. 즉, 취소, 재실행시는 스마트 공백 동작 안함
	if (bRec==TRUE && m_pEF->TestEditStyle(AES_SMARTSPACE) && m_cf.ViewMode!=HEXA_VIEW) {
		if (bCopy) {
			m_pEF->StartUndoGroup(26);
		} else {
			m_pEF->StartUndoGroup(27);
		}
		Insert(to,t,len,TRUE);
		se=to+len;
		nIns=AdjustSpaceInsert(to,se);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,TRUE);
				nIns=AdjustSpace(from,FALSE);
				to=to-len+nIns;
			} else {
				from+=nIns;
				Delete(from+len,len,TRUE);
				ss=from+len;
				AdjustSpace(ss,FALSE);
			}
		}
		m_pEF->EndUndoGroup();
	} else {
		Insert(to,t,len,FALSE);

		if (bCopy==FALSE) {
			if (to > from) {
				Delete(from,len,FALSE);
				to-=len;
			} else {
				Delete(from+len,len,FALSE);
			}
		}
		if (bRec) {
			if (bCopy) {
				m_pEF->URInsert(to,t,len);
			} else {
				m_pEF->URMove(from,orito,t,len);
			}
		}
	}
	free(t); 
}

void DETextCtrl::GetSelect(int &s, int &e,BOOL bRegular/*=TRUE*/)
{
	if (bRegular) {
		s=min(m_cf.SelStart,m_cf.SelEnd);
		e=max(m_cf.SelStart,m_cf.SelEnd);
	} else {
		s=m_cf.SelStart;
		e=m_cf.SelEnd;
	}
}

void DETextCtrl::SetSelect(int s, int e, BOOL bFind)
{
	if (s <= m_pEF->doclen && e <= m_pEF->doclen) {
		m_cf.SelStart=s;
		if (e == -1)
			e=m_pEF->doclen;
		m_cf.SelEnd=e;
	}
	m_cf.off=m_cf.SelEnd;
	SetCaret();
	if (bFind) {
		m_cf.bFindSelect=TRUE;
	}
	Invalidate(-1);
}

void DETextCtrl::SetLineRatio(int aLineHeight)
{
	int FirstRow;

	FirstRow=m_cf.yPos/m_cf.LineHeight;
	m_cf.LineRatio=aLineHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=FirstRow*m_cf.LineHeight;
	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::SetTabWidth(int aTabWidth)
{
	m_cf.TabWidth=aTabWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	UpdateLineInfo();
	UpdateScrollInfo();
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetFont(LOGFONT *alogfont)
{
	*alogfont=m_cf.logfont;
}

void DETextCtrl::SetFont(LOGFONT *alogfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hOldFont=NULL;

	if (m_cf.hMainFont) {
		DeleteObject(m_cf.hMainFont);
		m_cf.hMainFont=NULL;
	}

	m_cf.logfont=*alogfont;
	hdc=GetDC(m_hWnd);
	if (m_cf.logfont.lfHeight != 0) {
		if (m_pEF->CharRatio != 100) {
			m_cf.logfont.lfWidth=m_cf.logfont.lfHeight*m_pEF->CharRatio/200;
		} else {
			m_cf.logfont.lfWidth=0;
		}
		m_cf.hMainFont=CreateFontIndirect(&m_cf.logfont);
		hOldFont=(HFONT)SelectObject(hdc,m_cf.hMainFont);
	}
	PrepareCharWidth(hdc);
	GetTextMetrics(hdc,&tm);
	m_cf.FontHeight=tm.tmHeight;
	m_cf.LineHeight=int(m_cf.FontHeight*m_cf.LineRatio/100);
	m_cf.yPos=m_cf.yPos-(m_cf.yPos % m_cf.LineHeight);
	m_cf.FontWidth=tm.tmAveCharWidth;
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		m_cf.TabSize=m_cf.FontWidth*m_cf.TabWidth;
	} else {
		m_cf.TabSize=m_cf.SpaceWidth*m_cf.TabWidth;
	}
	if (hOldFont) {
		SelectObject(hdc,hOldFont);
	}
	ReleaseDC(m_hWnd,hdc);

	if (m_cf.hBit) {
		DeleteObject(m_cf.hBit);
		m_cf.hBit=NULL;
	}

	if (m_cf.pLine) {
		UpdateLineInfo();
		UpdateScrollInfo();
		SetCaret();
		Invalidate(-1);
	}
}

void DETextCtrl::SetDefaultSetting()
{
	if (m_cf.pLine) {
		SetLineRatio(120);
		SetWrap(2);
		SetTabWidth(4);
	} else {
		m_cf.LineRatio=120;
		m_cf.nWrap=2;
		EnableScrollBar(m_sbHorz,SB_CTL,ESB_DISABLE_BOTH);
		m_cf.TabWidth=4;
	}
	m_cf.MarginWidth = MARGINWIDTH;
	//m_cf.logfont.lfHeight=0;
	m_cf.hMainFont=NULL;

	SetFont(&m_cf.logfont);
	m_cf.RightWrap=0;
	m_cf.ColMark=0;
	SetParser(0);
	m_cf.bVirtualPos=FALSE;
	m_cf.bColumnMode=FALSE;
}

void DETextCtrl::SetRightWrap(int aRightWrap)
{
	m_cf.RightWrap=aRightWrap;
	SetWrap(m_cf.nWrap);
}

void DETextCtrl::SetColMark(int aColMark)
{
	m_cf.ColMark=aColMark;
	Invalidate(-1);
}

void DETextCtrl::SetParser(int ParseType)
{
	if (m_cf.Parser != NULL) {
		delete m_cf.Parser;
	}

	switch(ParseType) {
	case -1:
		break;
	case 0:
		m_cf.Parser = new DEParserPlain;
		break;
	case 1:
		m_cf.Parser = new DEParserCpp;
		break;
	case 2:
		m_cf.Parser = new DEParserHtml;
		break;
	case 3:
		m_cf.Parser = new DEParserSql;
		break;
	case 4:
		m_cf.Parser = new DEParserJava;
		break;
	case 5:
		m_cf.Parser = new DEParserCSharp;
		break;
	}

	Invalidate(-1);
}

//한번만 찾는다.
BOOL DETextCtrl::SearchText(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int *lpSearchCount)
{
	TCHAR szCom[256];
	int s,e;
	int OldyPos;

	wsprintf(szCom,"find \"%s\"",szFindStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	if (SearchTextSub(nPos,szFindStr,dwFindFlag,s,e)) {
		OldyPos = m_cf.yPos;
		SetSelect(s,e,TRUE);//블럭선택
		if (OldyPos != m_cf.yPos) {	
			ArrangeVerticalCenter(m_cf.SelStart);
		}
		int nCount = ShowSearchText(-1,dwFindFlag);
		if(lpSearchCount) *lpSearchCount = nCount;
		return TRUE;
	}
	else
		HideSearchText();
	return FALSE;
}

BOOL DETextCtrl::SearchTextSub(int nPos, LPTSTR szFindStr, DWORD dwFindFlag,int &s, int &e)
{
	int nStart;
	TCHAR *pFound;
	BOOL bWrap;
	TCHAR *pWhat;
	int len;

	pWhat = (TCHAR *)malloc(lstrlen(szFindStr)+1);
	if (strchr(szFindStr,'\\')==NULL) {
		lstrcpy(pWhat,szFindStr);
		len=lstrlen(pWhat);
	} else {
		len=AeEscapeString(szFindStr,pWhat);
	}
	
	nStart = nPos;
	if (nPos == -1) {//현재 캐럿위치부터
		if (m_cf.SelStart==m_cf.SelEnd) {
			nStart=m_cf.off;
		} else {
			if (dwFindFlag & AE_FIND_UP) {
				nStart=min(m_cf.SelStart,m_cf.SelEnd);//위로
			} else {
				nStart=max(m_cf.SelStart,m_cf.SelEnd);//아래로
			}
		}
	}
	bWrap = ((dwFindFlag & AE_FIND_WRAP)!=0);
	if(dwFindFlag & AE_FIND_UP) {
		nStart=nStart-len;
		if (nStart<0) {
			if (bWrap) {
				bWrap=FALSE;
				nStart=max(0,m_pEF->doclen-len);
			} else {
				free(pWhat);
				return FALSE;
			}
		}
	}

	for (;;) {
		pFound=FindString(m_pEF->buf,m_pEF->doclen,nStart,pWhat,len,(dwFindFlag & AE_FIND_UP)==0,
			(dwFindFlag & AE_FIND_MATCHCASE)!=0);
		if (pFound) {
			// 텍스트 뷰에서 DBCS 중간에 걸치면 검색 실패한 것으로 간주한다.
			if (m_cf.ViewMode != HEXA_VIEW && m_pEF->IsInDBCS(pFound-m_pEF->buf)) {
				if (dwFindFlag & AE_FIND_UP) {
					nStart=pFound-m_pEF->buf-1;
				} else {
					nStart=pFound-m_pEF->buf+len;
				}
				continue;
			}
			// 단어 단위로 검색할 경우 양쪽에 공백이 있어야 한다.
			if (dwFindFlag & AE_FIND_WHOLEWORD) {
				if ((pFound==m_pEF->buf || IsDelimiter(pFound-m_pEF->buf-1)) && 
					IsDelimiter(pFound-m_pEF->buf+len)) {
					break;
				} else {
					if (dwFindFlag & AE_FIND_UP) {
						nStart=pFound-m_pEF->buf-1;
					} else {
						nStart=pFound-m_pEF->buf+len;
					}
					continue;
				}
			}
			break;
		}

		if (bWrap) {
			bWrap=FALSE;
			if ((dwFindFlag & AE_FIND_UP)==0) {
				nStart=0;
			} else {
				nStart=max(0,m_pEF->doclen-len);
			}
			continue;
		}
		break;
	}

	free(pWhat);
	if (pFound) {
		s=pFound-m_pEF->buf;
		e=s+len;
		return TRUE;
	} else {
		s=e=-1;
		return FALSE;
	}
}

int DETextCtrl::ReplaceText(int nPos,LPTSTR szFindStr, DWORD dwFindFlag, LPTSTR szReplaceStr)
{
	int len,tolen;
	TCHAR *pSel;
	TCHAR *pWhat,*pTo;
	int Result;
	TCHAR szDesc[1024];
	TCHAR szCom[256];
	TCHAR *p;

	// 매크로 기록
	wsprintf(szCom,"replace \"%s\" \"%s\"",szFindStr,szReplaceStr);
	if ((dwFindFlag & AE_FIND_WRAP)==0)
		lstrcat(szCom," nowrap");
	if (dwFindFlag & AE_FIND_UP)
		lstrcat(szCom," up");
	if (dwFindFlag & AE_FIND_WHOLEWORD)
		lstrcat(szCom," word");
	if (dwFindFlag & AE_FIND_MATCHCASE)
		lstrcat(szCom," case");
	m_cmdH.pushCmd(szCom);

	// 검색되지 않은 상태에서 바꾸기이면 검색부터 한다.
	if (m_cf.SelStart == m_cf.SelEnd) {
		if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
			Result = 1;
		} else {
			Result = 0;
		}
	} else {
		// 확장열이면 먼저 변환한다.
		pWhat=(TCHAR *)malloc(lstrlen(szFindStr)+1);
		if (strchr(szFindStr,'\\')==NULL) {
			lstrcpy(pWhat,szFindStr);
			len = lstrlen(pWhat);
		} else {
			len = AeEscapeString(szFindStr,pWhat);
		}
		pTo=(TCHAR *)malloc(lstrlen(szReplaceStr)+1);
		if (strchr(szReplaceStr,'\\')==NULL) {
			lstrcpy(pTo,szReplaceStr);
			tolen = lstrlen(pTo);
		} else {
			tolen=AeEscapeString(szReplaceStr,pTo);
		}

		// 선택 영역의 텍스트를 읽는다.
		pSel=(TCHAR *)malloc(len);
		memcpy(pSel,m_pEF->buf+min(m_cf.SelStart,m_cf.SelEnd),len);

		// 대소 구분없이 비교한다면 모두 대문자로 변경한다.
		if ((dwFindFlag & AE_FIND_MATCHCASE) == 0) {
			for (p=pWhat;p-pWhat<len;p++) *p=toupper(*p);
			for (p=pSel;p-pSel<len;p++) *p=toupper(*p);
		}

		// 선택영역이 검색할 내용이 아니면 검색 명령을 대신 실행한다.
		if (memcmp(pWhat,pSel,len) != 0) {
			if (SearchText(nPos,szFindStr,dwFindFlag) == TRUE) {
				Result=1;
			} else {
				Result=0;
			}
		} else {
			// 선택영역을 지우고 대체 문자열을 삽입한다.
			wsprintf(szDesc," (%s -> %s)",szFindStr,szReplaceStr);
			m_pEF->StartUndoGroup(11,szDesc);
			DeleteSelection();
			Insert(m_cf.off,pTo,tolen);
			m_cf.off+=tolen;
			SetCaret();
			Invalidate(-1);
			// 다음 검색 결과가 없으면 0을 리턴하여 바꾸기를 중지한다.
			if (SearchText(m_cf.off,szFindStr,dwFindFlag) == TRUE) {
				Result=2;
			} else {
				Result=0;
			}
			m_pEF->EndUndoGroup();
		}
		free(pWhat);
		free(pTo);
		free(pSel);
	}
	return Result;
}

void DETextCtrl::GetSelRect(RECT &srt)
{
	int x1,y1,x2,y2;

	if (m_cf.SelStart==m_cf.SelEnd) {
		srt.left=-1;
		return;
	}

	GetXYFromOff(min(m_cf.SelStart,m_cf.SelEnd),x1,y1);
	GetXYFromOff(max(m_cf.SelStart,m_cf.SelEnd),x2,y2);

	x1-=m_cf.xPos;
	y1-=m_cf.yPos;
	x2-=m_cf.xPos;
	y2-=m_cf.yPos;

	if (y1==y2) {
		srt.left=x1;
		srt.top=y1;
		srt.right=x2;
		srt.bottom=y1+m_cf.FontHeight;
	} else {
		srt.left=m_cf.frt.left;
		srt.top=y1;
		srt.right=m_cf.frt.right;
		srt.bottom=y2+m_cf.FontHeight;
	}
}

int DETextCtrl::GetInfoFromOff(int Type, int nPos/*=-1*/)
{
	int r,c;
	int ret;

	if (nPos==-1) {
		nPos=m_cf.off;
	}

	GetRCFromOff(nPos,r,c);

	switch (Type) {
	case AE_INFO_ROW:
		ret=r;
		break;
	case AE_INFO_COL:
		ret=c;
		break;
	case AE_INFO_PARA:
		ret=m_cf.pLine[r].nPara;
		break;
	case AE_INFO_LINE:
		ret=m_cf.pLine[r].nLine;
		break;
	case AE_INFO_PARACOL:
		while (m_cf.pLine[r].nLine != 0) r--;
		return nPos-m_cf.pLine[r].begoff;
	}

	return ret;
}

void DETextCtrl::FindParen(BOOL bSelect)
{
	TCHAR ch,ch2;
	BOOL bFind;
	int Inc;
	int toff;
	int level;
	int i;
	int OldOff;

	bFind=FALSE;
	for (i=0;i>=-1;i--) {
		if (i==-1 && m_cf.off==0)
			break;
		ch=m_pEF->buf[m_cf.off+i];
		if (ch == '(' || ch == '{' || ch == '[' || ch == '<') {
			Inc=1;
			bFind=TRUE;
			break;
		}
		if (ch == ')' || ch == '}' || ch == ']' || ch == '>') {
			Inc=-1;
			bFind=TRUE;
			break;
		}
	}

	if (bFind==FALSE) {
		return;
	}
	OldOff=m_cf.off+i;

	switch (ch) {
	case '(': ch2=')'; break;
	case '{': ch2='}'; break;
	case '[': ch2=']'; break;
	case '<': ch2='>'; break;
	case ')': ch2='('; break;
	case '}': ch2='{'; break;
	case ']': ch2='['; break;
	case '>': ch2='<'; break;
	}

	level=0;
	for (toff=OldOff;;) {
		toff+=Inc;

		if (toff == m_pEF->doclen || toff == -1) {
			bFind=FALSE;
			break;
		}

		if (m_pEF->buf[toff]==ch2) {
			if (level == 0) {
				bFind=TRUE;
				break;
			}
			level--;
		}
		if (m_pEF->buf[toff]==ch)
			level++;
	}

	if (bFind) {
		m_cf.off=toff;
		if (bSelect) {
			if (Inc==1) {
				m_cf.off++;
			} else {
				OldOff++;
			}
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();/*m_cf.off로 캐럿이동*/

#ifdef DE_USE_FINDPAREN_TOPPOS
		int oldx,oldy;
		int x,y,py;
		int yInc = m_cf.LineHeight * 2;/*최소 2줄이 보여야함*/
		GetXYFromOff(OldOff,oldx,oldy);
		GetXYFromOff(m_cf.off,x,y);
		py = PureY(y);//top 마진 뺀 문서상의 그래픽단위 좌표(row * m_cf.LineHeight)
		int diffY = m_cf.yPos + yInc - py;//m_cf.yPos 는 현재 페이지의 top line의 스크롤 위치임
		if(oldy != y && diffY > 0){ /* 같은줄이 아닌 경우만 스크롤 처리함*/
			int nLine = diffY / m_cf.LineHeight + ((diffY % m_cf.LineHeight) ? 1 : 0);
			Scroll(-nLine);
		}
#endif
	}
}

void DETextCtrl::GotoLastEditOff()
{
	m_cmdH.pushCmd("move last");
	Move(AECM_LAST,FALSE);
}

int DETextCtrl::GetDocInfo(int type)
{
	int i;
	int count=0;
	int han=0;
	TCHAR *p=m_pEF->buf;

	switch (type) {
	case AE_DOC_TOTALPARA:
		return m_cf.pLine[m_cf.TotalLine-1].nPara;
	case AE_DOC_WORD:
		for (;!AeIsDocEnd(p);) {
			if (AeIsWhiteSpace(*p) || m_pEF->IsEnterCode(p)) {
				while ((AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n') && !AeIsDocEnd(p))
					p++;
			} else {
				count++;
				while (!AeIsWhiteSpace(*p) && *p!='\r' && *p!='\n' && !AeIsDocEnd(p)) 
					p++;
			}
		}
		break;
	case AE_DOC_EXSPACESIZE:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				count++;
			}
		}
		break;
	case AE_DOC_CHAR:
	case AE_DOC_HAN:
		for (;!AeIsDocEnd(p);p++) {
			if (!(AeIsWhiteSpace(*p) || *p=='\r' || *p=='\n')) {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					han++;
					p++;
				}
				count++;
			}
		}
		if (type == AE_DOC_HAN)
			return han;
		break;
	case AE_DOC_EMPTYLINE:
		for (i=0;i<=m_cf.pLine[m_cf.TotalLine-1].nPara;i++) {
			if (IsParaEmpty(m_pEF->buf+GetOffFromPara(i,0))) {
				count++;
			}
		}
		break;
	}
	return count;
}

void DETextCtrl::ChangeCase(int action)
{
	int SelFirst, SelSecond;
	int len;
	TCHAR *tbuf;
	TCHAR *p;
	int toff;

	if (m_pEF->bReadOnly) {
		return;
	}

	if (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd) {
		if (action < 3) {
			ChangeCaseColumn(action);
		}
		return;
	}

	if (m_cf.SelStart == m_cf.SelEnd) {
		switch (action) {
		case 0:
		case 1:
		case 2:
			if (AeIsDocEnd(m_pEF->buf+m_cf.off)) {
				return;
			}
			SelFirst=SelSecond=m_cf.off;
			if (m_pEF->IsDBCS(m_cf.off)) {
				len=2;
			} else {
				len=1;
			}
			break;
		case 3:
			GetNowWord(m_cf.off,SelFirst,SelSecond);
			len=SelSecond-SelFirst;
			break;
		case 4:
			return;
		}
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
		len=SelSecond-SelFirst;
	}

	tbuf=(TCHAR *)malloc(len);
	memcpy(tbuf,m_pEF->buf+SelFirst,len);

	switch (action) {
	case 0:
		m_cmdH.pushCmd("convert upper");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 1:
		m_cmdH.pushCmd("convert lower");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
			p++;
		}
		break;
	case 2:
		m_cmdH.pushCmd("convert reversecase");
		p=tbuf;
		while (p-tbuf < len) {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			} else if (IsCharLower(*p)) {
				*p-=0x20;
			}
			p++;
		}
		break;
	case 3:
		m_cmdH.pushCmd("convert upperfirst");
		p=tbuf;
		if (IsCharLower(*p)) {
			*p-=0x20;
		}
		p++;
		while (p-tbuf < len) {
			if (IsDelimiter(SelFirst+(p-tbuf)-1)) {
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	case 4:
		m_cmdH.pushCmd("convert uppersend");
		p=tbuf;

		toff=SelFirst;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
			toff--;
		if (toff==0 || m_pEF->IsEnterCode(toff-1) || m_pEF->buf[toff]=='.') {
			if (IsCharLower(*p)) {
				*p-=0x20;
			}
		} else {
			if (IsCharUpper(*p)) {
				*p+=0x20;
			}
		}
		p++;

		while (p-tbuf < len) {
			if (*p=='.' || m_pEF->IsEnterCode(tbuf,len,p-1)) {
				p++;
				while (AeIsWhiteSpace(*p) && p-tbuf < len)
					p++;
				if (p-tbuf == len)
					break;
				if (IsCharLower(*p)) {
					*p-=0x20;
				}
			} else {
				if (IsCharUpper(*p)) {
					*p+=0x20;
				}
			}
			p++;
		}
		break;
	}

	m_pEF->StartUndoGroup(3);
	Delete(SelFirst,len);
	Insert(SelFirst,tbuf,len);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart==m_cf.SelEnd && action < 3) {
		m_cf.off=m_pEF->GetNextOff(m_cf.off);
	}
	free(tbuf);
	Invalidate(SelFirst);
	SetCaret();
}

void DETextCtrl::ConvertSpaceTab(BOOL bToSpace)
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;
	int i;
	BOOL bFind;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	len=SelSecond-SelFirst;
	if (len==0) {
		return;
	}

	src=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);
	for (s=src,i=0;s-src != len;s++) {
		if (*s=='\t')
			i++;
	}
	dest=(TCHAR *)malloc(len+i*(m_cf.TabWidth-1));

	s=src;
	d=dest;
	nDiff=0;
	if (bToSpace) {
		m_cmdH.pushCmd("convert tospace");
		while (s-src < len) {
			if (*s=='\t') {
				for (i=0;i<m_cf.TabWidth;i++) {
					*d++=' ';
				}
				nDiff+=(m_cf.TabWidth-1);
				s++;
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(12);
	} else {
		m_cmdH.pushCmd("convert totab");
		while (s-src < len) {
			bFind=TRUE;
			for (i=0;i<m_cf.TabWidth;i++) {
				if (s[i]==0 || s[i]!=' ') {
					bFind=FALSE;
					break;
				}
			}

			if (bFind) {
				*d++='\t';
				s+=m_cf.TabWidth;
				nDiff+=(-m_cf.TabWidth+1);
			} else {
				*d++=*s++;
			}
		}
		m_pEF->StartUndoGroup(13);
	}
	*d=*s;
	SelSecond += nDiff;

	Delete(SelFirst,len);
	Insert(SelFirst,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
	} else {
		m_cf.SelStart=SelSecond;
	}

	Invalidate(SelFirst);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::RemoveExtraSpace()
{
	int SelFirst, SelSecond;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int len;
	int nDiff;

	if (m_pEF->bReadOnly) {
		return;
	}
	m_cmdH.pushCmd("convert removespace");
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}
	len=SelSecond-SelFirst;

	src=(TCHAR *)malloc(len);
	dest=(TCHAR *)malloc(len);
	memcpy(src,m_pEF->buf+SelFirst,len);

	s=src+len-1;
	d=dest+len-1;
	nDiff=0;
	for (;;) {
		*d=*s;
		if (s==src)
			break;
		d--;
		s--;

		if (m_pEF->IsEnterCode(src,len,s+1)) {
			while (AeIsWhiteSpace(*s) && s!=src) {
				s--;
				nDiff--;
			}
		}
	}

	if (nDiff) {
		m_pEF->StartUndoGroup(4);
		Delete(SelFirst,len);
		Insert(SelFirst,d,len+nDiff);
		m_pEF->EndUndoGroup();

		SelSecond += nDiff;

		if (m_cf.SelStart==m_cf.SelEnd) {
			m_cf.off=m_cf.SelStart=m_cf.SelEnd=0;
		} else if (m_cf.SelStart < m_cf.SelEnd) {
			m_cf.off=m_cf.SelEnd=SelSecond;
		} else {
			m_cf.SelStart=SelSecond;
		}

		Invalidate(SelFirst);
		SetCaret();
	}

	free(src);
	free(dest);
}

int DETextCtrl::GetParaFirstLine(int nPara)
{
	int Upper,Lower;
	int r;

	Lower=0;
	Upper=m_cf.TotalLine-1;
	if (nPara < 0 || nPara > m_cf.pLine[Upper].nPara) {
		return -1;
	}

	for (;;) {
		r=(Upper+Lower)/2;

		if (m_cf.pLine[r].nPara == nPara) {
			return r-m_cf.pLine[r].nLine;
		}

		if (m_cf.pLine[r].nPara > nPara) {
			Upper=r-1;
		} else {
			Lower=r+1;
		}
	}
}

int DETextCtrl::GetParaLastLine(int nPara)
{
	int r;

	r=GetParaFirstLine(nPara+1);
	if (r==-1) {
		return m_cf.TotalLine-1;
	} else {
		return r-1;
	}
}

void DETextCtrl::GetParaFromOff(int nPos, int &pr, int &pc)
{
	int r,c;

	GetRCFromOff(nPos,r,c);
	r=r-m_cf.pLine[r].nLine;

	pr=m_cf.pLine[r].nPara;
	pc=nPos-m_cf.pLine[r].begoff;
}

int DETextCtrl::GetOffFromPara(int pr, int pc)
{
	int r,re;

	r=GetParaFirstLine(pr);
	if (r==-1) {
		return -1;
	}
	re=GetParaLastLine(pr);

	if (m_cf.pLine[r].begoff+pc <= m_cf.pLine[re].endoff) {
		return m_cf.pLine[r].begoff+pc;
	} else {
		return -1;
	}
}

BOOL DETextCtrl::IsParaEmpty(TCHAR *p)
{
	for (;;p++) {
		if (AeIsLineEnd(p))
			return TRUE;
		if (!AeIsWhiteSpace(*p))
			return FALSE;
	}
}

int DETextCtrl::GetPrevPara(int nPos)
{
	int pr,pc;

	GetParaFromOff(nPos,pr,pc);
	if (pr > 0)	pr--;
	while (IsParaEmpty(m_pEF->buf+GetOffFromPara(pr,0)) && pr!=0) pr--;
	return pr;
}

int DETextCtrl::GetIndentLevel(TCHAR *p)
{
	int level;

	for (level=0;;p++) {
		if (*p=='\t') {
			level+=m_cf.TabWidth;
		} else if (*p==' '){
			level++;
		} else {
			break;
		}
	}
	return level;
}

void DETextCtrl::GetIndentString(int nPara,TCHAR *szIndent,int len)
{
	TCHAR *p1,*p2;

	p1=m_pEF->buf+GetOffFromPara(nPara,0);
	p2=szIndent;
	while (AeIsWhiteSpace(*p1)) {
		*p2++=*p1++;
		if (p2-szIndent == len-1)
			break;
	}
	*p2=0;
}

void DETextCtrl::MakeIndentString(int nTab, TCHAR *str, int len)
{
	int i;

	if (m_pEF->TestEditStyle(AES_SPACEFORTAB)) {
		for (i=0;i<nTab*m_cf.TabWidth && i < len-1;i++) {
			str[i]=' ';
		}
	} else {
		for (i=0;i<nTab && i < len-1;i++) {
			str[i]='\t';
		}
	}
	str[i]=0;
}

BOOL DETextCtrl::IsPrevParaBlockOpen(int nPos) 
{
	int tlen;
	int r;
	int toff;

	tlen=lstrlen(m_cf.Parser->GetInfo(5));
	if (tlen==0) {
		return FALSE;
	}

	r=GetParaLastLine(GetPrevPara(nPos));

	toff=m_cf.pLine[r].endoff;
	if (toff) 
		toff--;
	while (AeIsWhiteSpace(m_pEF->buf[toff]) && toff > 0)
		toff--;

	if (toff >= tlen-1) {
		toff=toff-tlen+1;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(5),tlen)==0) {
			return TRUE;
		}
	}
	return FALSE;
}

void DETextCtrl::ProcessIndent(TCHAR ch)
{
	TCHAR szIndent[4096];
	int toff;
	int tlen;
	BOOL bAllSpace;
	int nTab;

	if (ch == '\r') {
		if (IsPrevParaBlockOpen(m_cf.off)) {
			MakeIndentString(1,szIndent,4096);
			m_pEF->StartUndoGroup(9);
		} else {
			lstrcpy(szIndent,"");
			m_pEF->StartUndoGroup(8);
		}

		GetIndentString(GetPrevPara(m_cf.off),szIndent+lstrlen(szIndent),
			4096-lstrlen(szIndent));

		toff=m_cf.off;
		while (AeIsWhiteSpace(m_pEF->buf[toff]) && !AeIsLineEnd(m_pEF->buf+toff)) toff++;
		if (toff != m_cf.off) {
			Delete(m_cf.off,toff-m_cf.off);
		}

		if (lstrlen(szIndent)) {
			Insert(m_cf.off,szIndent,lstrlen(szIndent));
			m_cf.off+=lstrlen(szIndent);
		}
		m_pEF->EndUndoGroup();
	}

	tlen=lstrlen(m_cf.Parser->GetInfo(6));
	if (ch!='\r' && tlen && m_cf.off >= tlen) {
		toff=m_cf.off-tlen;
		if (_strnicmp(m_pEF->buf+toff,m_cf.Parser->GetInfo(6),tlen)==0) {
			for (;;) {
				toff--;
				if (m_pEF->buf[toff] == '\n' || toff==0) {
					bAllSpace=TRUE;
					break;
				}
				if (!AeIsWhiteSpace(m_pEF->buf[toff])) {
					bAllSpace=FALSE;
					break;
				}
			}

			if (bAllSpace) {
				GetIndentString(GetPrevPara(m_cf.off),szIndent,4096);

				nTab=GetIndentLevel(szIndent)/m_cf.TabWidth;

				if (!IsPrevParaBlockOpen(m_cf.off)) {
					nTab=max(0,nTab-1);
				}

				MakeIndentString(nTab, szIndent,4096);

				toff=m_pEF->FindParaStart(m_cf.off);
				m_pEF->StartUndoGroup(10);
				Delete(toff,m_cf.off-toff-tlen);
				if (lstrlen(szIndent)) {
					Insert(toff,szIndent,lstrlen(szIndent));
				}
				m_pEF->EndUndoGroup();

				m_cf.off=m_cf.off-(m_cf.off-toff-tlen)+lstrlen(szIndent);
			}
		}
	}
}

void DETextCtrl::BlockIndent(BOOL bUnindent)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nTab;
	TCHAR szIndent[1024];
	int nDec, nDiff;
	BOOL bFirstPara=TRUE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*m_cf.TabWidth);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnindent) {
		m_cmdH.pushCmd("convert indent");
		for (;;) {
			if (!IsParaEmpty(s)) {
				MakeIndentString(1,d,4096);
				d=d+lstrlen(d);
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1);
		}
		SelSecond+=(m_pEF->TestEditStyle(AES_SPACEFORTAB) ? m_cf.TabWidth:1)*nDiff;
	} else {
		m_cmdH.pushCmd("convert unindent");
		for (;;) {
			nTab=GetIndentLevel(s)/m_cf.TabWidth;

			nTab=max(0,nTab-1);

			MakeIndentString(nTab, szIndent,4096);

			nDec=0;
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDec++;
			}

			for (i=0;i<lstrlen(szIndent);i++) {
				*d++=szIndent[i];
			}

			nDiff+=(nDec-lstrlen(szIndent));
			if (bFirstPara) {
				SelFirst-=nDiff;
				SelFirst=max(SelFirst,st);
				bFirstPara=FALSE;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond-=nDiff;
	}

	m_pEF->StartUndoGroup(5);
	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertComment(BOOL bUnComment)
{
	int SelFirst, SelSecond;
	int st,ed;
	int pr1,pr2,pc;
	int Line;
	TCHAR *src,*dest;
	TCHAR *s,*d;
	int i;
	int nDiff;
	BOOL bFirstPara=TRUE;
	TCHAR szComment[32];
	int clen;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	lstrcpy(szComment,m_cf.Parser->GetInfo(2));
	clen=lstrlen(szComment);
	if (clen==0) {
		return;
	}

	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=SelSecond=m_cf.off;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff && m_cf.SelStart!=m_cf.SelEnd) {
		pr2--;
	}
	Line=GetParaLastLine(pr2);
	ed=m_cf.pLine[Line].endoff;

	src=(TCHAR *)malloc(ed-st);
	dest=(TCHAR *)malloc(ed-st+(pr2-pr1+1)*clen);
	memcpy(src,m_pEF->buf+st,ed-st);

	s=src;
	d=dest;
	nDiff=0;
	if (!bUnComment) {
		m_cmdH.pushCmd("convert comment");
		for (;;) {
			for (i=0;i<clen;i++) {
				*d++=szComment[i];
				nDiff++;
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}

		if (SelFirst!=st) {
			SelFirst+=clen;
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(14);
	} else {
		m_cmdH.pushCmd("convert uncomment");
		for (;;) {
			if (_strnicmp(s,szComment,clen)==0) {
				s+=clen;
				nDiff-=clen;

				if (bFirstPara) {
					SelFirst+=nDiff;
					SelFirst=max(SelFirst,st);
					bFirstPara=FALSE;
				}
			}

			while (!m_pEF->IsEnterCode(src,ed-st,s) && s != src+ed-st) {
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			} else {
				*d++=*s++;
				*d++=*s++;
			}
		}
		SelSecond+=nDiff;
		m_pEF->StartUndoGroup(15);
	}

	Delete(st,ed-st);
	Insert(st,dest,d-dest);
	m_pEF->EndUndoGroup();

	if (m_cf.SelStart == m_cf.SelEnd) {
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=SelSecond;
	} else if (m_cf.SelStart < m_cf.SelEnd) {
		m_cf.off=m_cf.SelEnd=SelSecond;
		m_cf.SelStart=SelFirst;
	} else {
		m_cf.off=m_cf.SelEnd=SelFirst;
		m_cf.SelStart=SelSecond;
	}

	Invalidate(st);
	SetCaret();
	free(src);
	free(dest);
}

void DETextCtrl::InsertText(TCHAR *Text)
{
	if (m_pEF->bReadOnly) {
		return;
	}

	InputExtraSpace(m_cf.off);
	BOOL bPrevSel;
	if (m_cf.SelStart != m_cf.SelEnd) {
		m_pEF->StartUndoGroup(1);
	}
	bPrevSel=DeleteSelection();

	Insert(m_cf.off,Text,lstrlen(Text));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(Text);
	SetCaret();

	if (bPrevSel) {
		m_pEF->EndUndoGroup();
	}
}

void DETextCtrl::CopyChar(int dir)
{
	int pr,pc;
	int col;
	int toff;
	TCHAR szTemp[3]={0,};
	BOOL bSpace=FALSE;

	if (m_pEF->bReadOnly || m_cf.ViewMode==HEXA_VIEW) {
		return;
	}

	GetParaFromOff(m_cf.off,pr,pc);
	if (dir==0) {
		m_cmdH.pushCmd("copychar up");
		if (pr > 0) {
			pr--;
		} else {
			return;
		}
	}
	if (dir==1) {
		m_cmdH.pushCmd("copychar down");
		if (pr < m_cf.pLine[m_cf.TotalLine-1].nPara) {
			pr++;
		} else {
			return;
		}
	}

	ClearSelection();

	toff=GetOffFromPara(pr,0);
	for (col=0;;) {
		if (AeIsLineEnd(m_pEF->buf+toff)) {
			return;
		}
		if (col==pc) {
			break;
		}
		if (col>pc) {
			bSpace=TRUE;
			break;
		}
		if (m_pEF->IsDBCS(toff)) {
			toff+=2;
			col+=2;
		} else {
			toff++;
			col++;
		}
	}

	if (bSpace) {
		szTemp[0]=' ';
	} else {
		szTemp[0]=m_pEF->buf[toff];
		if (m_pEF->IsDBCS(toff)) {
			szTemp[1]=m_pEF->buf[toff+1];
		}
	}
	Insert(m_cf.off,szTemp,lstrlen(szTemp));
	Invalidate(m_pEF->FindParaStart(m_cf.off));
	m_cf.off=m_cf.off+lstrlen(szTemp);
	SetCaret();
}

void DETextCtrl::BeginPrint(DEPRINTINFO *pi)
{
	int l,s,e;
	int nPara=0, nLine=0;
	SIZE sz;
	TEXTMETRIC tm;
	int ParseID;
	int Alignlen;

	if (pi->ParseID == -1) {
		ParseID=(int)GetParser()->GetInfo(0);
	} else {
		ParseID=pi->ParseID;
	}

	switch (ParseID) {
	default:
		pi->Parser=NULL;
		break;
	case 1:
		pi->Parser=new DEParserCpp;
		break;
	case 2:
		pi->Parser=new DEParserHtml;
		break;
	case 3:
		pi->Parser=new DEParserSql;
		break;
	}

	GetTextMetrics(pi->pdc,&tm);
	if (m_pEF->TestEditStyle(AES_CALCTABWITHAVG)) {
		sz.cx=tm.tmAveCharWidth;
	} else {
		GetTextExtentPoint32(pi->pdc," ",1,&sz);
	}
	pi->TabSize=sz.cx*m_cf.TabWidth;
	pi->LineHeight=int(tm.tmHeight*m_cf.LineRatio/100);
	pi->LinePerPage=(pi->prt.bottom-pi->prt.top)/pi->LineHeight;

	Alignlen=m_cf.TotalLine*2;
	pi->pLine=(DELINEINFO *)malloc(sizeof(DELINEINFO)*Alignlen);
	for (l=0;;l++) {
		if (l >= Alignlen) {
			Alignlen += 1000;
			pi->pLine=(DELINEINFO *)realloc(pi->pLine,sizeof(DELINEINFO)*Alignlen);
		}
		GetLine(l,s,e,pi);

		pi->pLine[l].begoff=s;
		pi->pLine[l].endoff=e;
		pi->pLine[l].nPara=nPara;
		pi->pLine[l].nLine=nLine;
		if (s==-1) {
			break;
		}

		if (m_pEF->IsEnterCode(e)) {
			nPara++;
			nLine=0;
		} else {
			nLine++;
		}
	}

	if (pi->Parser) {
		pi->Parser->ParseLines(*this,l,pi);
	}
	pi->TotalPage=(l-1)/pi->LinePerPage+1;
}

void DETextCtrl::GetLine(int Line, int &s, int &e,DEPRINTINFO *pi)
{
	TCHAR *p,*Head;
	int len, acwidth;
	TCHAR *EndPos=NULL;
	TCHAR *EndPosNoSpace=NULL;
	BOOL IsPrevDBCS=FALSE;
	SIZE sz;

	pi->Origin=pi->prt.left;
	if (pi->bLineNum) {
		GetTextExtentPoint32(pi->pdc,"999999",6,&sz);
		pi->Origin+=sz.cx;
	}

	if (Line == 0) {
		p=m_pEF->buf;
		s=0;
	} else {
		p=m_pEF->buf+pi->pLine[Line-1].endoff;
		if (AeIsDocEnd(p)) {
			s=-1;
			e=-1;
			return;
		}

		if (m_pEF->IsEnterCode(p)) {
			p+=2;
		}

		s=p-m_pEF->buf;
	}

	if (pi->nWrap == 0) {
		while (!AeIsLineEnd(p)) {
			if (m_pEF->IsDBCS(p-m_pEF->buf)) {
				p++;
			}
			p++;
		}
	} else {
		for (acwidth=pi->Origin,Head=p;;) {
			if (*p == '\t') {
				len=1;
				acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
				EndPos=p;
			} else {
				if (m_pEF->IsDBCS(p-m_pEF->buf)) {
					len=2;

					if (pi->nWrap==2 || (pi->nWrap==3 && p != Head && IsPrevDBCS==FALSE)) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=TRUE;
				} else {
					len=1;

					if (IsPrevDBCS==TRUE) {
						EndPos=p;
						if (*EndPos != ' ') {
							EndPosNoSpace=EndPos;
						}
					}
					IsPrevDBCS=FALSE;
				}
				GetTextExtentPoint32(pi->pdc,p,len,&sz);
				acwidth+=sz.cx;
			}

			if (AeIsLineEnd(p)) {
				EndPos=p;
				break;
			}

			if (acwidth > pi->prt.right) {
				break;
			}

			if (*p == ' ' || *p=='\t') {
				EndPos=p+1;
				if (*EndPos != ' ') {
					EndPosNoSpace=EndPos;
				}
			}

			p+=len;
		}
	}

	if (pi->nWrap == 1 || EndPos == NULL) {
		p=p;
	} else {
		p=EndPos;
	}
	if (m_pEF->TestEditStyle(AES_NOFIRSTSPACE) && *p==' ' && EndPosNoSpace!=NULL) {
		p=EndPosNoSpace;
	}
	e=p-m_pEF->buf;
}

BOOL DETextCtrl::PrintPage(DEPRINTINFO *pi,int nPage)
{
	int l,Line;
	int len;
	int nowoff;
	int x;
	SIZE sz;
	int style;
	BOOL bFindTextBlock;
	COLORREF fore, back;
	TCHAR szLine[32];
	COLORREF OldTextColor, OldBkColor;
	int OldBkMode;
	BOOL bEnd=FALSE;

	OldTextColor=GetTextColor(pi->pdc);
	OldBkColor=GetBkColor(pi->pdc);
	OldBkMode=GetBkMode(pi->pdc);
	for (l=pi->LinePerPage*(nPage-1),Line=0;l<pi->LinePerPage*nPage;l++,Line++) {
		if (pi->pLine[l].begoff == -1) {
			bEnd=TRUE;
			break;
		}

		x=pi->Origin;
		nowoff=pi->pLine[l].begoff;
		for (;;) {
			for (len=0;;) {
				if (m_pEF->buf[nowoff+len] == '\t') {
					if (len==0)
						len=1;
					break;
				}
				if (nowoff+len==pi->pLine[l].endoff) {
					break;
				}

				if (pi->Parser) {
					bFindTextBlock = FALSE;
					int nPara = pi->pLine[l].nPara;
					if(pi->Parser->GetSearchBlockStyle(nPara,nowoff + len,TRUE) != -2)//-2 즉,검색에 포함안되거나 검색하지 않은 상태가 아니면 스타일이 있다고 봐야한다.그래야 len을 정확히 끊음
						bFindTextBlock = TRUE;
					else if(pi->Parser->GetStyle(nPara,nowoff + len,TRUE) != -1)
						bFindTextBlock = TRUE;

					if (bFindTextBlock && len!=0)
						break;
				}
				len++;
			}
			LOGFONT lfseg;
			DETEXTSTYLE textStyle;

			if (pi->Parser && len!=0) {
				//현재위치 nowoff + len 보다 작은 이전 구간의 스타일
				int nPara = pi->pLine[l].nPara;
				style = pi->Parser->GetSearchBlockStyle(nPara,nowoff);
				if(style < 0)
					style = pi->Parser->GetStyle(nPara,nowoff);
				pi->Parser->GetTextStyle(style,textStyle);
				fore = textStyle.fore;
				back = textStyle.back;

				if (fore!=-1) {
					SetTextColor(pi->pdc,fore);
				} else {
					SetTextColor(pi->pdc,RGB(0,0,0));
				}
				if (back!=-1) {
					SetBkColor(pi->pdc,back);
					SetBkMode(pi->pdc,OPAQUE);
				} else {
					SetBkMode(pi->pdc,TRANSPARENT);
				}
			}else {
				SetTextColor(pi->pdc,RGB(0,0,0));
				SetBkMode(pi->pdc,TRANSPARENT);
			}
			lfseg = m_cf.logfont;
			lfseg.lfWeight = textStyle.bBold ? FW_BOLD : FW_NORMAL;
			lfseg.lfUnderline = textStyle.bUnderline;
			lfseg.lfItalic = textStyle.bItalic;
		
			HFONT hsegFont = NULL;
			HFONT hOldFont = NULL;
		
			if(memcmp(&lfseg,&m_cf.logfont,sizeof(LOGFONT))){
				hsegFont = CreateFontIndirect(&lfseg);
				hOldFont = (HFONT)SelectObject(pi->pdc,hsegFont);
			}
			if (m_pEF->buf[nowoff] == '\t') {
				x =((x-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;
			} else {
				ExtTextOut(pi->pdc,x,pi->prt.top+Line*pi->LineHeight,
					ETO_CLIPPED,&pi->prt,m_pEF->buf+nowoff,len,NULL);
				GetTextExtentPoint32(pi->pdc,m_pEF->buf+nowoff,len,&sz);
				x+=sz.cx;
			}
			if(hsegFont){
				DeleteObject(hsegFont);
				SelectObject(pi->pdc,hOldFont);
			}
			nowoff+=len;
			if (nowoff==pi->pLine[l].endoff) {
				break;
			}
		}

		if (pi->bLineNum) {
			if (pi->pLine[l].nLine==0) {
				wsprintf(szLine,"%d",pi->pLine[l].nPara);
				SetTextColor(pi->pdc,RGB(128,128,128));
				SetBkMode(pi->pdc,TRANSPARENT);
				TextOut(pi->pdc,pi->prt.left,pi->prt.top+Line*pi->LineHeight,
					szLine,lstrlen(szLine));
			}
		}
	}
	SetTextColor(pi->pdc,OldTextColor);
	SetBkColor(pi->pdc,OldBkColor);
	SetBkMode(pi->pdc,OldBkMode);

	return bEnd;
}

void DETextCtrl::EndPrint(DEPRINTINFO *pi)
{
	free(pi->pLine);
	if (pi->Parser) {
		delete pi->Parser;
	}
}

void DETextCtrl::InitView()
{
	int i;

	m_cf.Parser->InitInfo(TRUE);
	m_cf.Linelen=100;
	if (m_cf.pLine) {
		free(m_cf.pLine);
	}
	m_cf.pLine = (DELINEINFO *)malloc(sizeof(DELINEINFO)*m_cf.Linelen);
	for (i = 0;i < m_cf.Linelen; i++) {
		m_cf.pLine[i].begoff =-1;
	}
	m_cf.bOvr=FALSE;
	m_cf.off=0;
	m_cf.PrevX=0;
	m_cf.bLineEnd=FALSE;
	m_cf.xMax=1024;
	m_cf.xPos=0;
	m_cf.yPos=0;
	m_cf.SelStart=m_cf.SelEnd=0;
	ClearBookmark();
	UpdateLineInfo();
	UpdateScrollInfo();
	if (GetFocus()==m_hWnd) {
		SetCaret();
	}
	m_cf.bPrevCompoGroup=FALSE;
	m_cf.iDrag=0;
	m_cf.OldSplit=0;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt=0;
	m_cf.SelExtraX=0;
	Invalidate(-1);
}

void DETextCtrl::SetOffset(int aoff)
{
	m_cf.off=aoff;
	SetCaret();
}

void DETextCtrl::SetVertSplit(BOOL aValue)
{
	if (m_cf.bVertSplit!=aValue) {
		m_cf.bVertSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

void DETextCtrl::SetHorzSplit(BOOL aValue)
{
	if (m_cf.bHorzSplit!=aValue) {
		m_cf.bHorzSplit=aValue;
		SendMessage(m_hWnd,WM_SIZE,0,0);
	}
}

BOOL DETextCtrl::StartSplit(HWND hWnd,BOOL fDoubleClick,POINT point)
{
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.bVertSplit && point.x > crt.right-SBW && point.y < SPLITWIDTH) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_VERT,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_VERT;
	}
	if (m_cf.bHorzSplit && point.x < SPLITWIDTH && point.y > crt.bottom-SBW) {
		if (fDoubleClick) {
			m_pEF->SplitView(AESPLIT_HORZ,5000);
			return TRUE;
		}
		m_cf.iDrag=AESPLIT_HORZ;
	}
	if (m_cf.iDrag) {
		SetCapture(hWnd);
		m_cf.bCapture=TRUE;
		m_cf.OldSplit=0;
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::Spliting(HWND hWnd,POINT point)
{
	int tx,ty;
	RECT FrameRect;

	GetClientRect(m_pEF->m_hWnd,&FrameRect);
	if (m_cf.iDrag == AESPLIT_VERT) {
		ty=min(max(point.y,FrameRect.top),FrameRect.bottom-VGAP);
		if (m_cf.OldSplit != ty) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=ty;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	if (m_cf.iDrag ==AESPLIT_HORZ) {
		tx=min(max(point.x,FrameRect.left),FrameRect.right-VGAP);
		if (m_cf.OldSplit != tx) {
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
			m_cf.OldSplit=tx;
			m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		}
		return TRUE;
	}
	return FALSE;
}

BOOL DETextCtrl::EndSplit(HWND hWnd,POINT point)
{
	int Ratio;
	RECT crt;

	GetClientRect(hWnd,&crt);
	if (m_cf.iDrag) {
		m_pEF->DrawSplitBar(m_cf.iDrag,m_cf.OldSplit);
		if (m_cf.iDrag==AESPLIT_VERT) {
			Ratio=point.y*10000/(crt.bottom-crt.top);
		} else {
			Ratio=point.x*10000/(crt.right-crt.left);
		}
		if (Ratio > 500 && Ratio < 9500) {
			m_pEF->SplitView(m_cf.iDrag,Ratio);
		}
		m_cf.iDrag=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::AeTextOut(HDC hdc,int x,int y,TCHAR *str,int len)
{
	int i;
	int boff;

	boff=str-m_pEF->buf;
	for (i=0;i<len;) {
		if (m_pEF->IsDBCS(boff+i)) {
			m_cf.lpDx[i++]=GetCharWidth(str+i,2);
			m_cf.lpDx[i++]=0;
		} else {
			m_cf.lpDx[i++]=GetCharWidth(str+i,1);
		}
	}
	ExtTextOut(hdc,x,y,0,NULL,str,len,m_cf.lpDx);
}

void DETextCtrl::SetBookmark(int *aMark) 
{
	memcpy(m_cf.arMark,aMark,sizeof(int)*MAXBOOKMARK);
	Invalidate(-1);
}

void DETextCtrl::SetVirtualPos(int aValue)
{
	m_cf.bVirtualPos=aValue;
	if (m_cf.bVirtualPos==FALSE && m_cf.ExtraX > 0) {
		m_cf.ExtraX=0;
		SetCaret();
	}
}

BOOL DETextCtrl::IsVirtualPosable()
{
	if (m_cf.bVirtualPos || (m_cf.bColumnMode && m_cf.SelStart != m_cf.SelEnd)) {
		if (m_cf.ignoreVirt > 0) {
			return FALSE;
		} else {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL DETextCtrl::InputExtraSpace(int &nPos)
{
	TCHAR *pExSpace;

	if (m_cf.ExtraX > 0) {
		pExSpace=(TCHAR *)malloc(m_cf.ExtraX+1);
		memset(pExSpace,' ',m_cf.ExtraX);
		pExSpace[m_cf.ExtraX]=0;
		Insert(nPos,pExSpace,m_cf.ExtraX);
		nPos+=m_cf.ExtraX;
		free(pExSpace);
		m_cf.ExtraX=0;
		return TRUE;
	}
	return FALSE;
}

void DETextCtrl::SetColumnMode(int aMode)
{
	LOGFONT tFont;
	HFONT hFont;

	m_cf.bColumnMode=aMode;
	if (m_cf.bColumnMode==FALSE) {
		if (m_cf.SelStart != m_cf.SelEnd) {
			if (m_cf.ExtraX != 0) {
				m_cf.ExtraX=0;
				SetCaret();
			}
			m_cf.SelExtraX=0;
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN) && m_cf.Bklogfont.lfHeight!=-1) {
			SetFont(&m_cf.Bklogfont);
			m_cf.Bklogfont.lfHeight=-1;
		}
	} else {
		if (m_pEF->TestEditStyle(AES_NOWRAPCOLUMN) && GetWrap()!=0) {
			SetWrap(0);
		}
		if (m_pEF->TestEditStyle(AES_FIXEDCOLUMN)) {
			if (m_pEF->FixedFont.lfHeight==0) {
				hFont=(HFONT)GetStockObject(SYSTEM_FIXED_FONT);
				GetObject(hFont,sizeof(LOGFONT),&tFont);
			} else {
				tFont= m_pEF->FixedFont;
			}
			GetFont(&m_cf.Bklogfont);
			SetFont(&tFont);
		}
	}

	if (m_cf.SelStart != m_cf.SelEnd) {
		Invalidate(-1);
	}
}

void DETextCtrl::GetSelInLine(int Line,int &s,int &e)
{
	int SelFirst, SelSecond;
	int sx,sy;
	int ex,ey;
	int left,right;
	int BkExtraX;

	s=e=0;

	if (m_cf.SelStart == m_cf.SelEnd) {
		return;
	}

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	if (SelFirst > m_cf.pLine[Line].endoff || SelSecond <= m_cf.pLine[Line].begoff) {
		return;
	}

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	GetXYFromOff(m_cf.SelStart,sx,sy);
	GetXYFromOff(m_cf.SelEnd,ex,ey);
	ex+=m_cf.SelExtraX*m_cf.SpaceWidth;
	left=min(sx,ex);
	right=left+abs(sx-ex);

	s=GetOffFromXY(left,DocY(Line*m_cf.LineHeight));
	e=GetOffFromXY(right,DocY(Line*m_cf.LineHeight));
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

int DETextCtrl::MakeSelTable()
{
	int Size;
	int SelFirst, SelSecond;
	int c,rs,re,Line;
	int idx;
	int len=0;

	if (!m_cf.bColumnMode || m_cf.SelStart == m_cf.SelEnd) return 0;
	Size=100;
	m_cf.SelTable=(DESELBLOCK *)malloc(Size*sizeof(DESELBLOCK));

	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	GetRCFromOff(SelFirst,rs,c);
	GetRCFromOff(SelSecond,re,c);
	for (Line=rs,idx=0;Line<=re;Line++,idx++) {
		if (idx == Size-1) {
			Size+=100;
			m_cf.SelTable=(DESELBLOCK *)realloc(m_cf.SelTable,Size*sizeof(DESELBLOCK));
		}
		m_cf.SelTable[idx].nLine=Line;
		GetSelInLine(Line,m_cf.SelTable[idx].begoff,m_cf.SelTable[idx].endoff);
		len+=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff+2;
	}
	m_cf.SelTable[idx].nLine=-1;
	
	return len;
}

void DETextCtrl::FreeSelTable()
{
	if (m_cf.SelTable) free(m_cf.SelTable);
	m_cf.SelTable=NULL;
}

void DETextCtrl::PasteColumn(int nPos,int aExtra,TCHAR *data)
{
	int PasteX,Line,dummy,y;
	int nLine;
	int toff;
	int BkVirtualPos;

	BkVirtualPos=m_cf.bVirtualPos;
	m_cf.bVirtualPos=TRUE;

	GetXYFromOff(nPos,PasteX,dummy);
	GetRCFromOff(nPos,Line,dummy);

	for (nLine=Line;;nLine++) {
		if (*data==(TCHAR)0xff) {
			break;
		}
		if (nLine == m_cf.TotalLine) {
			Insert(m_pEF->doclen,"\r\n",2);
		}
		GetXYFromOff(m_cf.pLine[nLine].begoff,dummy,y);
		toff=GetOffFromXY(PasteX,y);

		if (lstrlen(data)) {
			InputExtraSpace(toff);
			Insert(toff,data,lstrlen(data));
		}
		data+=lstrlen(data)+1;
	}
	m_cf.bVirtualPos=BkVirtualPos;
}

void DETextCtrl::ColumnCopyString(BOOL bCopy,int to,int aExtra)
{
	TCHAR *Src,*ptr;
	int len,idx,linelen;
	int Acc;

	len=MakeSelTable();
	Src=(TCHAR *)malloc(len+1);
	ptr=Src;
	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
		memcpy(ptr,m_pEF->buf+m_cf.SelTable[idx].begoff,linelen);
		ptr+=linelen;
		*ptr++=0;
	}
	*ptr=(TCHAR)0xff;

	if (bCopy) {
		m_pEF->StartUndoGroup(18);
	} else {
		m_pEF->StartUndoGroup(19);
		for (idx=0,Acc=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
			linelen=m_cf.SelTable[idx].endoff-m_cf.SelTable[idx].begoff;
			Delete(m_cf.SelTable[idx].begoff-Acc,linelen);
			if (m_cf.SelTable[idx].begoff < to) {
				to-=linelen;
			}
			Acc+=linelen;
		}
	}
	FreeSelTable();

	PasteColumn(to,aExtra,Src);
	m_pEF->EndUndoGroup();
	free(Src);

	m_cf.SelStart=m_cf.SelEnd=m_cf.off=to+aExtra;
	SetCaret();
	Invalidate(-1);
}

void DETextCtrl::ChangeCaseColumn(int action)
{
	int idx;
	int bkSelStart,bkSelEnd;

	MakeSelTable();
	m_cf.bColumnMode=FALSE;
	bkSelStart=m_cf.SelStart;
	bkSelEnd=m_cf.SelEnd;
	m_pEF->StartUndoGroup(20);

	for (idx=0;m_cf.SelTable[idx].nLine!=-1;idx++) {
		m_cf.SelStart=m_cf.SelTable[idx].begoff;
		m_cf.SelEnd=m_cf.SelTable[idx].endoff;
		if (m_cf.SelStart!=m_cf.SelEnd) {
			ChangeCase(action);
		}
	}
	
	m_pEF->EndUndoGroup();
	m_cf.bColumnMode=TRUE;
	m_cf.SelStart=bkSelStart;
	m_cf.SelEnd=bkSelEnd;
	FreeSelTable();
}

void DETextCtrl::ProcessKey(UINT vk,BOOL bControl,BOOL bShift)
{
	int r,c;
	int oldr;
	int OldOff;
	int toff;

	ProcessKeyRecord(vk,bControl,bShift);

	switch (vk) {
	case VK_F2:
		if (bControl) {
			ToggleBookmark(-1,100);
		} else {
			if (bShift) {
				GotoBookmark(11);
			} else {
				GotoBookmark(10);
			}
		}
		break;
	case VK_F6:
		m_pEF->ChangeActiveView(this,(bShift ? 2:1));
		break;
	case VK_LEFT:
		if (m_cf.off > 0) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetPrevWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX--;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].begoff) {
						if (m_pEF->IsEnterCode(m_pEF->GetPrevOff(m_cf.off)) || 
							m_pEF->TestEditStyle(AES_USELINEEND)==FALSE) {
							m_cf.off=m_pEF->GetPrevOff(m_cf.off);
							m_cf.bLineEnd=FALSE;
						} else {
							m_cf.bLineEnd=TRUE;
						}
					} else {
						m_cf.off=m_pEF->GetPrevOff(m_cf.off);
						m_cf.bLineEnd=FALSE;
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_RIGHT:
		if (m_cf.off < m_pEF->doclen || IsVirtualPosable()) {
			GetRCFromOff(m_cf.off,r,c);

			OldOff=m_cf.off;
			if (bControl) {
				m_cf.off=GetNextWord(m_cf.off);
				m_cf.ExtraX=0;
			} else {
				if (m_cf.ExtraX > 0) {
					if (IsVirtualPosable()) {
						m_cf.ExtraX++;
					} else {
						m_cf.ExtraX=0;
					}
				} else {
					if (m_cf.off==m_cf.pLine[r].endoff) {
						if (AeIsLineEnd(m_pEF->buf+m_cf.off)) {
							if (IsVirtualPosable()) {
								m_cf.ExtraX++;
							} else {
								m_cf.off=m_pEF->GetNextOff(m_cf.off);
							}
						}
						m_cf.bLineEnd=FALSE;
					} else {
						m_cf.off=m_pEF->GetNextOff(m_cf.off);
						if (m_cf.off==m_cf.pLine[r].endoff && !m_pEF->IsEnterCode(m_cf.off) && 
							m_pEF->TestEditStyle(AES_USELINEEND)) {
							m_cf.bLineEnd=TRUE;
						} else {
							m_cf.bLineEnd=FALSE;
						}
					}
				}
			}

			if (bShift) {
				ExpandSelection(OldOff,m_cf.off);
			} else {
				if (m_cf.SelStart != m_cf.SelEnd) {
					m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				}
			}
			SetCaret();
		}

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		
		OldOff=m_cf.off;
		if (r > 0) {
			if (bControl) {
				SendMessage(m_hWnd, WM_VSCROLL, SB_LINEUP, 0L);
				if (r != (m_cf.Fheight+m_cf.yPos)/m_cf.LineHeight)
					break;
			}
			m_cf.off=GetXPosOnLine(r-1,m_cf.PrevX);
		// 첫 줄에서 위로 이동은 문서 처음으로 이동한다.
		} else {
			m_cf.off=0;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=min(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_UP,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		GetRCFromOff(m_cf.off,r,c);
		if (bControl) {
			SendMessage(m_hWnd, WM_VSCROLL, SB_LINEDOWN, 0L);
			if (r != m_cf.yPos/m_cf.LineHeight-1) {
				break;
			}
		}

		OldOff=m_cf.off;
		if (r < GetRowCount()-1) {
			m_cf.off=GetXPosOnLine(r+1,m_cf.PrevX);
		// 마지막 줄에서 아래로 이동은 문서의 끝으로 이동이다.
		} else {
			m_cf.off=m_pEF->doclen;
		}

		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			if (m_cf.SelStart != m_cf.SelEnd) {
				m_cf.off=max(m_cf.SelStart, m_cf.SelEnd);
				ClearSelection();
				SetCaret(!m_cf.bVirtualPos);
				SendMessage(m_hWnd,WM_KEYDOWN,VK_DOWN,(LPARAM)0);
			}
		}
		SetCaret(FALSE);

		if (!bShift) {
			ClearSelection();
		}
		break;
	case VK_PRIOR:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r-=m_cf.Fheight/m_cf.LineHeight;
		r=max(r,0);
		m_cf.yPos=m_cf.yPos-(oldr-r)*m_cf.LineHeight;
		m_cf.yPos=max(m_cf.yPos,0);
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 첫줄에서는 문서 처음으로 이동한다.
		if (r == 0) {
			m_cf.off=0;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_NEXT:
		GetRCFromOff(m_cf.off,r,c);
		oldr=r;
		r+=m_cf.Fheight/m_cf.LineHeight;
		r=min(r,GetRowCount()-1);
		m_cf.yPos=m_cf.yPos+(r-oldr)*m_cf.LineHeight;
		m_cf.yPos=max(0,min(m_cf.yPos,m_cf.yMax-(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight));
		Invalidate(-1);
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);

		OldOff=m_cf.off;
		// 마지막 줄이면 문서 끝으로 이동한다.
		if (r == GetRowCount()-1) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.off=GetXPosOnLine(r,m_cf.PrevX);
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret(FALSE);
		break;
	case VK_HOME:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=0;
		} else {
			m_cf.off=GetOffFromRC(r,0);
			if (m_pEF->TestEditStyle(AES_HOMETOFIRSTCHAR)) {
				toff=m_cf.off;
				while (AeIsWhiteSpace(m_pEF->buf[toff])) 
					toff++;
				if (OldOff!=toff && !AeIsLineEnd(m_pEF->buf+toff)) {
					m_cf.off=toff;
				}
			}
		}
		m_cf.bLineEnd=FALSE;
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		SetCaret();
		break;
	case VK_END:
		GetRCFromOff(m_cf.off,r,c);
		OldOff=m_cf.off;
		if (bControl) {
			m_cf.off=m_pEF->doclen;
		} else {
			m_cf.ignoreVirt++;
			m_cf.off=GetOffFromRC(r,1000000);
			m_cf.ignoreVirt--;
		}
		if (!AeIsLineEnd(m_pEF->buf+m_cf.off)) {
			m_cf.bLineEnd=TRUE;
		}
		if (bShift) {
			ExpandSelection(OldOff,m_cf.off);
		} else {
			ClearSelection();
		}
		//마지막 줄인데 스크롤 위치가 부적절하면 위치 보정,이현상은 스크롤 MAX 
		//(m_cf.yMax)에 전체 row만큼 + 화면 1/2 을 추가
		//하여 나온 현상이다.따라서 이곳에서 보정해준다. UpdateScrollInfo 참조
#ifdef DE_USE_ADJUSTSCROLLPOS
		if(bControl){
			m_cf.yPos = max(m_cf.yPos,m_cf.yMax - m_cf.yPage);
			if (IsWindowEnabled(m_sbVert))
				SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
			Invalidate(-1);
		}
#endif
		SetCaret();
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_CUT,0),0);
			break;
		}
		if (DeleteSelection()==FALSE) {
			if (m_pEF->IsDBCS(m_cf.off)) {
				Delete(m_cf.off, 2);
			} else {
				Delete(m_cf.off, 1);
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (DeleteSelection()==FALSE) {
			if (bControl) {
				OldOff=m_cf.off;
				m_cf.off=GetPrevWord(OldOff);
				Delete(m_cf.off,OldOff-m_cf.off);
			} else {
				m_cf.off=m_pEF->GetPrevOff(m_cf.off);
				if (m_pEF->IsDBCS(m_cf.off)) {
					Delete(m_cf.off, 2);
				} else {
					Delete(m_cf.off, 1);
				}
			}
		}
		Invalidate(m_pEF->FindParaStart(m_cf.off));
		SetCaret();
		break;
	case VK_INSERT:
		if (bShift) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_PASTE,0),0);
		} else if (bControl) {
			SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_COPY,0),0);
		} else {
			m_cf.bOvr = !m_cf.bOvr;
			m_pEF->SendNotify(AEN_INSMODE);
			SetCaret();
		}
		break;
	}
}

void DETextCtrl::Move(int n, BOOL bSelect)
{
	int pr, pc;
	int toff;

	GetParaFromOff(m_cf.off,pr,pc);
	switch (n) {
	case AECM_LAST:
		toff=m_pEF->LastEditOff;
		break;
	case AECM_WORDHOME:
		toff=m_cf.off;
		if (toff == 0)
			break;
		// 단어 끝 구분자에 있는 경우를 위해 일단 한칸 앞으로 이동.
		for (toff--;;toff--) {
			if (IsDelimiter(toff) || toff==0)
				break;
		}
		if (toff !=0)
			toff++;
		break;
	case AECM_WORDEND:
		for (toff=m_cf.off;;toff++) {
			if (IsDelimiter(toff))
				break;
		}
		break;
	case AECM_NEXTPARA:
		pr++;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PREVPARA:
		pr--;
		toff=GetOffFromPara(pr,0);
		if (toff==-1) {
			return;
		}
		break;
	case AECM_PARAHOME:
		toff=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		break;
	case AECM_PARAEND:
		GetParaFromOff(m_cf.off,pr,pc);
		toff=m_cf.pLine[GetParaLastLine(pr)].endoff;
		break;
	default:
		return;
	}

	if (bSelect) {
		ExpandSelection(m_cf.off,toff);
		m_cf.off=toff;
	} else {
		m_cf.off=toff;
		ClearSelection();
	}
	SetCaret();
}

void DETextCtrl::Select(int n)
{
	int r,c;
	int pr,pc;

	switch (n) {
	case AECS_WORD:
		GetNowWord(m_cf.off,m_cf.SelStart,m_cf.SelEnd);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_LINE:
		GetRCFromOff(m_cf.off,r,c);
		m_cf.SelStart=m_cf.pLine[r].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[r].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_PARA:
		GetParaFromOff(m_cf.off,pr,pc);
		m_cf.SelStart=m_cf.pLine[GetParaFirstLine(pr)].begoff;
		m_cf.SelEnd=m_pEF->IncludeEnter(m_cf.pLine[GetParaLastLine(pr)].endoff);
		SetSelect(m_cf.SelStart,m_cf.SelEnd,FALSE);
		break;
	case AECS_DOC:
		SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDM_AE_SELALL,0),0);
		break;
	default:
		return;
	}
}

void DETextCtrl::Scroll(int nLine, int nCode/*=0*/)
{
	int yInc;
	int LinePerPage;
	RECT srt;

	if (nCode) {
		switch (nCode) {
		case 1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEDOWN,0),0);
			return;
		case -1:
			SendMessage(m_hWnd,WM_VSCROLL,MAKELONG(SB_PAGEUP,0),0);
			return;
		case 2:
			nLine=m_cf.Fheight/m_cf.LineHeight/2;
			break;
		case -2:
			nLine=-m_cf.Fheight/m_cf.LineHeight/2;
			break;
		}
	}
	LinePerPage=(m_cf.Fheight/m_cf.LineHeight)*m_cf.LineHeight;
	yInc=m_cf.LineHeight*nLine;
	yInc=max(-m_cf.yPos, min(yInc, m_cf.yMax-m_cf.yPos-LinePerPage));
	yInc=yInc-(yInc % m_cf.LineHeight);
	m_cf.yPos=m_cf.yPos+yInc;
	srt=m_cf.frt;
	srt.left=0;
	if (m_pEF->hBackBit && m_pEF->BackBitPos!=AEBB_TILESCROLL) {
		Invalidate(-1);
	} else {
		ScrollWindow(m_hWnd, 0, -yInc, &srt, &srt);
	}
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	ManageCaret();
}

void DETextCtrl::ProcessKeyRecord(UINT nChar,BOOL bControl,BOOL bShift)
{
	switch (nChar) {
	case VK_LEFT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wleft");
			} else {
				m_cmdH.pushCmd("movesel left");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wleft");
			} else {
				m_cmdH.pushCmd("move left");
			}
		}
		break;
	case VK_RIGHT:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel wright");
			} else {
				m_cmdH.pushCmd("movesel right");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move wright");
			} else {
				m_cmdH.pushCmd("move right");
			}
		}
		break;
	case VK_UP:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel up");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll up");
			} else {
				m_cmdH.pushCmd("move up");
			}
		}
		break;
	case VK_DOWN:
		if (bControl && bShift)
			break;
		if (bShift) {
			m_cmdH.pushCmd("movesel down");
		} else {
			if (bControl) {
				m_cmdH.pushCmd("scroll down");
			} else {
				m_cmdH.pushCmd("move down");
			}
		}
		break;
	case VK_PRIOR:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgup");
		} else {
			m_cmdH.pushCmd("move pgup");
		}
		break;
	case VK_NEXT:
		if (bShift) {
			m_cmdH.pushCmd("movesel pgdn");
		} else {
			m_cmdH.pushCmd("move pgdn");
		}
		break;
	case VK_HOME:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel dochome");
			} else {
				m_cmdH.pushCmd("movesel home");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move dochome");
			} else {
				m_cmdH.pushCmd("move home");
			}
		}
		break;
	case VK_END:
		if (bShift) {
			if (bControl) {
				m_cmdH.pushCmd("movesel docend");
			} else {
				m_cmdH.pushCmd("movesel end");
			}
		} else {
			if (bControl) {
				m_cmdH.pushCmd("move docend");
			} else {
				m_cmdH.pushCmd("move end");
			}
		}
		break;
	case VK_DELETE:
		if (m_pEF->bReadOnly || m_cf.bCapture)
			break;
		if (!bShift) {
			m_cmdH.pushCmd("delete");
		}
		break;
	case VK_BACK:
		if (m_pEF->bReadOnly || m_cf.bCapture || m_cf.ViewMode==HEXA_VIEW)
			break;
		if ((m_cf.off==0 && m_cf.SelStart==m_cf.SelEnd) || (bShift && bControl))
			break;

		if (bControl) {
			m_cmdH.pushCmd("bs word");
		} else {
			m_cmdH.pushCmd("bs char");
		}
		break;
	}
}

void DETextCtrl::EndComp()
{
	HIMC hImc;
	if (m_cf.bComp) {
		hImc=ImmGetContext(m_hWnd);
		ImmNotifyIME(hImc,NI_COMPOSITIONSTR,CPS_COMPLETE,0);
		ImmReleaseContext(m_hWnd,hImc);
	}
}

// 상용구 삽입. 삽입 후 캐럿 이동, 선택까지 해야 한다.
void DETextCtrl::InsertClipText(TCHAR *Text)
{
	TCHAR *pTemp;
	TCHAR *s,*d;
	int ts=-1,te=-1;
	int len;

	m_pEF->StartUndoGroup(22);
	DeleteSelection();
	len=lstrlen(Text);
	pTemp=(TCHAR *)malloc(len+1);
	for (s=Text,d=pTemp;*s;) {
		// 뒤쪽에 최소한 3바이트 남았을 때 점검
		if (s-Text <= len-3 && s[0]=='^' && s[1]=='|' && s[2]=='^') {
			// 처음 발견되었을 때 오프셋 기록
			if (ts==-1) {
				ts=m_cf.off+(s-Text);
			// 두번째 발견되었을 때 끝 오프셋 기록. 세번째 이후는 무시
			} else if (te==-1) {
				te=m_cf.off+(s-Text)-3;
			}
			// 건너 뜀
			s+=3;
		} else {
			*d++=*s++;
		}
	}
	*d=0;

	InsertText(pTemp);
	if (te != -1) {
		SetSelect(ts,te,FALSE);
	} else if (ts != -1) {
		SetOffset(ts);
	} else {
		SetCaret();
	}
	free(pTemp);
	m_pEF->EndUndoGroup();
}

void DETextCtrl::TestAutoClip(int ch)
{
	TCHAR *pWord;
	int toff,len;

	// 최소한 2글자는 입력되어 있어야 검색의 의미가 있다.
	if (m_pEF->TestEditStyle(AES_USEAUTOCLIP) && m_cf.off >= 2) {
		if ((m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB) && ch=='\t') || 
			(m_pEF->TestEditStyle(AES_AUTOCLIPBYTAB)==FALSE && ch==' ')) {
			toff=GetAutoClipName();
			len=m_cf.off-1-toff;
			// len이 0인 경우 : 계속 공백만 이어지는 경우. 앞쪽 단어가 없음
			if (len) {
				pWord=(TCHAR *)calloc(len+1,1);
				memcpy(pWord,m_pEF->buf+toff,len);
				if (SendMessage(::GetParent(m_pEF->m_hWnd),m_pEF->UserBase+3,0,(LPARAM)pWord)) {
					Invalidate(m_pEF->FindParaStart(toff));
				}
				free(pWord);
			}
		}
	}
}

int DETextCtrl::GetAutoClipName()
{
	int toff;
	
	// 앞쪽의 공백 아닌 문자를 찾음. 구분자 개념이 없으므로 GetPrevWord 등을 쓸 수 없음
	for (toff=m_cf.off-2;;toff--) {
		if (AeIsWhiteSpace(m_pEF->buf[toff]) || m_pEF->buf[toff] == '\n') {
			toff++;
			break;
		}
		if (toff==0) {
			break;
		}
	}
	return toff;
}

// 직전의 단어를 Text 상용구로 대체한다.
void DETextCtrl::ReplaceClipText(TCHAR *Text)
{
	int toff;

	toff=GetAutoClipName();
	m_pEF->StartUndoGroup(23);
	Delete(toff,m_cf.off-toff);
	m_cf.off=toff;
	InsertClipText(Text);
	m_pEF->EndUndoGroup();
}

// 스크롤 상태를 고려하여 캐럿을 숨기거나 보인다.
void DETextCtrl::ManageCaret()
{
	POINT pt;
	GetXYFromOff(m_cf.off,(int &)pt.x,(int &)pt.y);
	pt.y-=m_cf.yPos;
	pt.x-=m_cf.xPos;

	// 포맷팅 영역을 벗어나면 숨긴다.
	if (PtInRect(&m_cf.frt,pt)==FALSE) {
		if (m_cf.bHideCaret==FALSE) {
			HideCaret(m_hWnd);
			m_cf.bHideCaret=TRUE;
		}
	} else {
		ShowCaret(m_hWnd);
		m_cf.bHideCaret=FALSE;
	}
	// 캐럿이 아직 보이는 상태면 이동한다.
	if (m_cf.bHideCaret==FALSE) {
		SetCaret(FALSE,FALSE);
	}
}

void DETextCtrl::DrawRuler(HWND hWnd,HDC hdc)
{
	TCHAR szTemp[10];
	RECT crt,rrt;
	HBRUSH hBrush;
	HPEN hPen,OldPen;
	HFONT hOldFont;
	int i,x;

	GetClientRect(hWnd,&crt);

	DETEXTSTYLE rulerStyle;
	m_cf.Parser->GetTextStyle(STYLEINDEX_RULER,rulerStyle);
	COLORREF crback = (rulerStyle.back != -1) ? rulerStyle.back : m_pEF->GetColorBack(STYLEINDEX_RULER);
	COLORREF crfore = (rulerStyle.fore != -1) ? rulerStyle.fore : m_pEF->GetColorFore(STYLEINDEX_RULER);

	hBrush = CreateSolidBrush(crback);
	//SetRect(&rrt,m_cf.MarginWidth,0,crt.right-SBW,RULERHEIGHT);
	SetRect(&rrt,0,0,crt.right-SBW,RULERHEIGHT);
	FillRect(hdc,&rrt,hBrush);
	hPen=CreatePen(PS_SOLID,1,crfore);
	OldPen=(HPEN)SelectObject(hdc,hPen);
	
	//MoveToEx(hdc,m_cf.MarginWidth,RULERHEIGHT-1,NULL);
	MoveToEx(hdc,0,RULERHEIGHT-1,NULL);
	LineTo(hdc,crt.right-SBW,RULERHEIGHT-1);
	hOldFont=(HFONT)SelectObject(hdc,DEEditCtrl::hLineNumFont);
	SetTextAlign(hdc,TA_CENTER);
	for (i=0;;i++) {
		x=m_cf.frt.left+m_cf.FontWidth*i;
		MoveToEx(hdc,x,RULERHEIGHT-1,NULL);
		if (i%10==0) {
			wsprintf(szTemp,"%d",i);
			TextOut(hdc,x,2,szTemp,lstrlen(szTemp));
		}
		if (i%5==0) {
			LineTo(hdc,x,RULERHEIGHT-9);
		} else {
			LineTo(hdc,x,RULERHEIGHT-5);
		}
		// 출력한 후 좌표 점검해야 마지막 눈금까지 출력된다.
		if (x > crt.right-SBW) {
			break;
		}
	}
	SetTextAlign(hdc,TA_LEFT);
	SelectObject(hdc,hOldFont);
	DeleteObject(SelectObject(hdc,OldPen));
	DeleteObject(hBrush);
}

int DETextCtrl::GetCharYPos()
{
	switch (m_pEF->VAlign) {
	case 0:
		return 0;
	default:
	case 1:
		return (m_cf.LineHeight-m_cf.FontHeight)/2;
	case 2:
		return m_cf.LineHeight-m_cf.FontHeight;
	}
}

void DETextCtrl::DrawSelFrame(HDC hdc)
{
	HRGN hRgn;
	int x1,y,x2;
	int SelFirst, SelSecond;
	HBRUSH hBrush;
	int rs,re,i;
	int ss,se;
	RECT rt;
	HRGN rgn;
	BOOL OldbLineEnd;
	int BkExtraX;

	BkExtraX=m_cf.ExtraX;
	m_cf.ExtraX=0;
	m_cf.ignoreVirt++;

	OldbLineEnd=m_cf.bLineEnd;
	SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
	SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	m_cf.bLineEnd=FALSE;
	GetRCFromOff(SelFirst,rs,i);
	m_cf.bLineEnd=TRUE;
	GetRCFromOff(SelSecond,re,i);
	hRgn=CreateRectRgn(0,0,0,0);

	for (i=rs;i<=re;i++) {
		if (m_cf.bColumnMode) {
			GetSelInLine(i,ss,se);
		} else {
			if (i==rs) {
				ss=SelFirst;
			} else {
				ss=m_cf.pLine[i].begoff;
			}
			if (i==re) {
				se=SelSecond;
			} else {
				se=m_cf.pLine[i].endoff;
			}
		}
		m_cf.bLineEnd=FALSE;
		GetXYFromOff(ss,x1,y);
		m_cf.bLineEnd=TRUE;
		GetXYFromOff(se,x2,y);
		if (!m_cf.bColumnMode && m_pEF->IsEnterCode(se) && se >= SelFirst && se < SelSecond) {
			if (m_pEF->TestEditStyle(AES_SHOWENTER)) {
				switch (m_pEF->GetShowEnterType()) {
				case 0:
					x2+=m_cf.SpaceWidth*2;
					break;
				case 1:
					x2+=m_cf.SpaceWidth*3;
					break;
				case 2:
					x2+=m_cf.SpaceWidth*3;
					break;
				}
			} else {
				x2+=m_cf.SpaceWidth;
			}
		}
		x1-=m_cf.xPos;
		y-=m_cf.yPos;
		x2-=m_cf.xPos;
		SetRect(&rt,x1,y,x2,y+m_cf.LineHeight);
		if (PtInRect(&m_cf.frt,*(POINT *)&rt) || PtInRect(&m_cf.frt,*(POINT *)&rt.right)) {
			rgn=CreateRectRgnIndirect(&rt);
			CombineRgn(hRgn,hRgn,rgn,RGN_OR);
			DeleteObject(rgn);
		}
	}

	hBrush = CreateSolidBrush(m_pEF->GetColorBack(STYLEINDEX_SELBORDER));
	FrameRgn(hdc,hRgn,hBrush,2,2);
	DeleteObject(hBrush);
	DeleteObject(hRgn);
	m_cf.bLineEnd=OldbLineEnd;
	m_cf.ignoreVirt--;
	m_cf.ExtraX=BkExtraX;
}

void DETextCtrl::DrawBackBit(HDC hdc,int nLine)
{
	int sLine;
	HDC hMemDC;
	HBITMAP OldBitmap;
	BITMAP bit;
	int bx,by,ys,xs;
	int ax,ay,bs;

	hMemDC=CreateCompatibleDC(hdc);
	OldBitmap=(HBITMAP)SelectObject(hMemDC,m_pEF->hBackBit);
	GetObject(m_pEF->hBackBit,sizeof(BITMAP),&bit);
	bx=bit.bmWidth;
	by=bit.bmHeight;

	// 6번외에는 화면상의 줄 수를 기준으로 한다.
	if (m_pEF->BackBitPos==AEBB_TILESCROLL) {
		sLine=nLine;
	} else {
		sLine=nLine-m_cf.yPos/m_cf.LineHeight;
	}

	switch (m_pEF->BackBitPos) {
	case AEBB_LEFTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_RIGHTTOP:
		if (sLine*m_cf.LineHeight < by) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight,SRCCOPY);
		}
		break;
	case AEBB_LEFTBOTTOM:
		// 비트맵 출력 시작 위치 = 포맷팅 영역 높이 - 비트맵 높이
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		// 현재줄의 시작 좌표가 비트맵 출력 시작 좌표 이상이면. 대응되는 비트맵 부분 출력
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,m_cf.frt.left,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		// 끝 좌표가 비트맵 출력 좌표 이상이면(비트맵이 출력되는 첫줄에만 해당된다)
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,m_cf.frt.left,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_RIGHTBOTTOM:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by);
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,max(m_cf.frt.right-bx,m_cf.frt.left),ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_CENTER:
		ys=max(0,(m_cf.frt.bottom-m_cf.frt.top)-by)/2;
		xs=max(0,(m_cf.frt.right-m_cf.frt.left)-bx)/2;
		if (sLine*m_cf.LineHeight >= ys) {
			BitBlt(hdc,xs,0,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				sLine*m_cf.LineHeight-ys,SRCCOPY);
		} else if (sLine*m_cf.LineHeight+m_cf.LineHeight-1 >= ys) {
			BitBlt(hdc,xs,ys % m_cf.LineHeight,m_cf.frt.right,m_cf.LineHeight,hMemDC,0,
				0,SRCCOPY);
		}
		break;
	case AEBB_TILE:
	case AEBB_TILESCROLL:
		// by-bs : 실제 출력된 높이. 비트맵 출력 시작점 이후의 남은 픽셀수.
		for (ay=0;ay < m_cf.LineHeight;ay+=(by-bs)) {
			// 출력을 시작할 비트맵의 수직 좌표
			if (ay==0) {
				bs=sLine*m_cf.LineHeight % by;
			} else {
				bs=0;
			}
			// 수평으로 반복 출력
			for (ax=m_cf.frt.left;;ax+=bx) {
				if (ax >= m_cf.frt.right) {
					break;
				}
				BitBlt(hdc,ax,ay,ax+bx,m_cf.LineHeight,hMemDC,0,
					bs,SRCCOPY);
			}
		}
		break;
	}
	
	SelectObject(hMemDC,OldBitmap);
	DeleteDC(hMemDC);
}

void DETextCtrl::ProcessCursorInEditing()
{
	RECT crt;
	POINT pt;

	switch (m_pEF->CursorEdit) {
	default:
	case 0:
		break;
	case 1:
		ShowCursorEdit(FALSE);
		break;
	case 2:
	case 3:
		GetClientRect(m_hWnd,&crt);
		ClientToScreen(&crt);
		if (m_pEF->CursorEdit==2) {
			SetCursorPos(crt.right-25,crt.top+8);
		} else {
			SetCursorPos(crt.right-25,crt.bottom-33);
		}
		break;
	case 4:
		GetCaretPos(&pt);
		ClientToScreen(&pt);
		SetCursorPos(pt.x+m_cf.FontWidth*5,pt.y+m_cf.LineHeight*2);
		break;
	}
}

void DETextCtrl::ShowCursorEdit(BOOL bShow)
{
	if (bShow) {
		if (!m_cf.bShowCursor) {
			ShowCursor(TRUE);
			m_cf.bShowCursor=TRUE;
		}
	} else {
		if (m_cf.bShowCursor) {
			ShowCursor(FALSE);
			m_cf.bShowCursor=FALSE;
		}
	}
}

// nPos 자리에 공백 조정. 리턴값은 삽입된 바이트 수
int DETextCtrl::AdjustSpace(int &nPos,BOOL bAdd)
{
	int toff;
	int s,e;

	// 공백 시작 오프셋
	for (toff=nPos-1;;toff--) {
		if (toff==0) {
			s=toff;
			break;
		}
		if (m_pEF->buf[toff]!= ' ') {
			s=toff+1;
			break;
		}
	}
	// 공백 끝 오프셋
	for (toff=s;;toff++) {
		if (toff==m_pEF->doclen) {
			e=toff;
			break;
		}
		if (m_pEF->buf[toff]!=' ') {
			e=toff;
			break;
		}
	}

	// 문단 처음이고 공백이 있을 경우. 모든 공백 삭제
	if (e-s > 0 && m_pEF->FindParaStart(s)==s) {
		Delete(s,e-s);
		nPos=s;
		return -(e-s);
	}
	// 1보다 크면 하나만 남기고 삭제
	if (e-s > 1) {
		Delete(s+1,e-s-1);
		nPos=s+1;
		return -(e-s-1);
	}
	// 공백이 없고 bAdd이면 공백 하나 삽입
	if (bAdd && e-s==0) {
		Insert(nPos," ",1);
		nPos++;
		return 1;
	}
	// 원래 공백이 하나이거나 공백이 없었던 경우.
	return 0;
}

// 양쪽에 공백 정리.
int DETextCtrl::AdjustSpaceInsert(int &nPos1,int &nPos2)
{
	int nIns;

	// 문단 처음은 뒤쪽만 조정하면 된다.
	if (nPos1==m_pEF->FindParaStart(nPos1)) {
		nIns=AdjustSpace(nPos2,TRUE);
		return nIns;
	}

	// 양쪽에 공백이 없으면 조정할 필요가 없음.
	if ((nPos1==0 || m_pEF->buf[nPos1-1]!=' ') && m_pEF->buf[nPos2]!=' ')
		return 0;

	// 앞쪽 조정. nPos2 같이 이동
	nIns=AdjustSpace(nPos1,TRUE);
	nPos2+=nIns;

	// 뒤쪽 조정. nPos2는 조정 후의 공백 앞 위치
	nIns+=AdjustSpace(nPos2,TRUE);
	return nIns;
}

// 선택된 문단의 시작, 끝 버퍼 오프셋을 구해준다.
void DETextCtrl::SelectParas(int &SelFirst,int &SelSecond,int &st,int &ed)
{
	int pr1,pr2,pc;
	int Line;

	// 선택 영역이 없으면 문서 전체를 대상으로 한다.
	if (m_cf.SelStart==m_cf.SelEnd) {
		SelFirst=0;
		SelSecond=m_pEF->doclen;
	} else {
		SelFirst=min(m_cf.SelStart,m_cf.SelEnd);
		SelSecond=max(m_cf.SelStart,m_cf.SelEnd);
	}

	// 시작 문단의 첫 오프셋
	GetParaFromOff(SelFirst,pr1,pc);
	Line=GetParaFirstLine(pr1);
	st=m_cf.pLine[Line].begoff;

	// 끝 문단의 끝 오프셋. 선택 끝이 문단 선두이면 이 문단은 제외된다.
	GetParaFromOff(SelSecond,pr2,pc);
	Line=GetParaFirstLine(pr2);
	if (SelSecond==m_cf.pLine[Line].begoff) {
		pr2--;
	}
	if(pr2 < 0)
		ed = st;//krkim
	else{
		Line=GetParaLastLine(pr2);
		ed=m_cf.pLine[Line].endoff;
	}
}

//bugfix kkr add check (ed-st > 0) ? and return for exception

#define BEFOREARRANGEPARA 	\
	int SelFirst, SelSecond;\
	int st,ed,nDiff=0;\
	TCHAR *src,*dest,*s,*d;\
	SelectParas(SelFirst,SelSecond,st,ed);\
	s = src = (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	d = dest= (ed-st > 0) ? (TCHAR *)malloc(ed-st) : NULL; \
	if(!s || m_pEF->doclen == 0) \
		return; \
	memcpy(src,m_pEF->buf+st,ed-st);

#define ENDARRANGEPARA(grpid) \
	SelSecond-=nDiff;\
	m_pEF->StartUndoGroup(grpid);\
	Delete(st,ed-st);\
	Insert(st,dest,d-dest);\
	m_pEF->EndUndoGroup();\
	if (m_cf.SelStart == m_cf.SelEnd) {\
		m_cf.off=m_cf.SelStart=m_cf.SelEnd=st;\
	} else if (m_cf.SelStart < m_cf.SelEnd) {\
		m_cf.off=m_cf.SelEnd=SelSecond;\
		m_cf.SelStart=SelFirst;\
	} else {\
		m_cf.off=m_cf.SelEnd=SelFirst;\
		m_cf.SelStart=SelSecond;\
	}\
	if (m_pEF->IsInDBCS(m_cf.off)) m_cf.off=m_pEF->GetPrevOff(m_cf.off);\
	if (m_pEF->IsInDBCS(m_cf.SelStart)) m_cf.SelStart=m_pEF->GetPrevOff(m_cf.SelStart);\
	if (m_pEF->IsInDBCS(m_cf.SelEnd)) m_cf.SelEnd=m_pEF->GetPrevOff(m_cf.SelEnd);\
	Invalidate(st);\
	SetCaret();\
	free(src);\
	free(dest);

//CRLF를 대체 문자열로 바꾼다
//nContinuousEnter : 연속으로딸린 CRLF 처리 : 0 = 같이,1 = 대상에서 제외 , 2 = 삭제해버림
//szRep : 대체문자열
void DETextCtrl::MergePara(int nContinuousEnter,TCHAR *szReplaceText)
{
	BEFOREARRANGEPARA
	BOOL bPrevEnter=FALSE;
	int rLen = (szReplaceText) ? lstrlen(szReplaceText) : 0 ;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			if (nContinuousEnter != 0 && bPrevEnter) {
				if (nContinuousEnter == 1) {//제외
					*d++=*s++;
					*d++=*s++;
				} else { // 삭제
					s+=2;
					nDiff+=2;
				}
			} else { //대체
				if(szReplaceText)
					lstrcpy(d,szReplaceText);
				d += rLen;
				s += 2;
				nDiff += 2 - rLen;
				bPrevEnter=TRUE;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
			bPrevEnter=FALSE;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(28)
}

//CRLF 추가로 문단분리
//nType : 0 = 윈도우범위 1 = nCol 로 컬럼폭으로 
//       2 = nCol 로 픽셀폭으로 3 = szSplitText 앞에서 분리, 4 = szSplitText 뒤에서 분리
//bRemoveSpace : 분리된 이후 다음 라인의 앞부분 공백제거
//nIndentType : 0 = 분리후 공백으로 들여쓰기 1 = 내어쓰기, 2 = 탭으로 들여쓰기 (nType = 1,2 일때만 적용)
//nIndent : 문자수 , 0 = 없음
//bCase = 1 대소문자 구분
void DETextCtrl::SplitPara(int nType, int nCol, BOOL bRemoveSpace,int nIndentType,int nIndent,BOOL bCase,TCHAR *szSplitText)
{
	BEFOREARRANGEPARA
	int acwidth;
	int sl,el,l;
	int *arWrap,idx;
	int i;
	int stLen = (szSplitText) ? lstrlen(szSplitText) : 0 ;
	CHAR *sp = NULL;

	switch (nType)
	{
	case 0://윈도우 범위
		GetRCFromOff(st,sl,l);
		GetRCFromOff(ed,el,l);
		arWrap=(int *)malloc((el-sl)*sizeof(int));
		// el줄은 문단 끝이므로 볼 필요없음. l+1은 항상 유효함
		for (l=sl,idx=0;l<el;l++) {
			if (m_cf.pLine[l+1].nLine) {
				arWrap[idx]=m_cf.pLine[l].endoff;
				idx++;
			}
		}

		for (idx=0;;) {
			ReallocBuf(dest,d,1024,2048);
			// 현재 오프셋이 자동 개행된 오프셋과 같으면
			if (s-src+st == arWrap[idx]) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
				idx++;
				// 마침표 다음의 공백은 건너 뜀
				if (bRemoveSpace) {
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				if (IsDBCSLeadByte(*s)) {
					*d++=*s++;
				}
				*d++=*s++;
			}
			if (s==src+ed-st) {
				break;
			}
		}
		free(arWrap);
		break;
	// 중간에 문단 구조가 바뀌기 때문에 m_cf.pLine 배열은 참조할 수 없음
	case 1://컬럼
	case 2://픽셀수
		ReallocBuf(dest,d,1024,2048);
		acwidth = 0;
		// 문단 처음은 항상 들여쓰기 한다.
		if (nIndentType == 0 || nIndentType == 2) {//들여쓰기(공백,탭)
			for (i = 0;i < nIndent; i++) {
				*d++= (nIndentType == 2) ? '\t' : ' ';
				nDiff--;
				if (nType == 1){//컬럼문자수로
					acwidth++;
				} else {//픽셀로
					if(nIndentType == 2)
						acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
					else
						acwidth += GetCharWidth(" ",1);
				}
			}
			// 공백은 건너 뛰어야 한다.
			while (AeIsWhiteSpace(*s)) {
				s++;
				nDiff++;
			}
		}
		for (;;) {
			ReallocBuf(dest,d,1024,2048);
			if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n'){
				*d++=*s++;
				*d++=*s++;
				acwidth=0;
				// 들여쓰기 한다.
				if (nIndentType == 0 || nIndentType == 2) {//들여쓰기
					for (i = 0;i < nIndent; i++) {
						*d++= (nIndentType == 2) ? '\t' : ' ';
						nDiff--;
						if (nType == 1) {//컬럼문자수로
							acwidth++;
						} else {//픽셀로
							if(nIndentType == 2)
								acwidth = (acwidth/m_cf.TabSize + 1) * m_cf.TabSize;
							else
								acwidth += GetCharWidth(" ",1);
						}
					}
					// 공백은 건너 뛰어야 한다. 들여쓰기를 하지 않을 때는 그냥 둔다
					while (AeIsWhiteSpace(*s)) {
						s++;
						nDiff++;
					}
				}
			} else {
				// 현재 문자까지 더했을 때의 폭을 계산한다.
				if (nType == 1) {//문자
					if (IsDBCSLeadByte(*s)) {
						acwidth+=2;
					} else {
						acwidth++;
					}
				} else {
					if (*s == '\t') {
						acwidth = (acwidth/m_cf.TabSize+1)*m_cf.TabSize;
					} else {
						if (IsDBCSLeadByte(*s)) {
							acwidth += GetCharWidth(s,2);
						} else {
							acwidth += GetCharWidth(s,1);
						}
					}
				}
				// 폭을 넘었을 때 분할. 같을 때는 분할하지 않음
				if (acwidth > nCol) {
					*d++='\r';
					*d++='\n';
					acwidth=0;
					nDiff-=2;
					// 삽입된 개행코드 다음의 공백은 건너 뜀
					if (bRemoveSpace) {
						while (AeIsWhiteSpace(*s)) {
							s++;
							nDiff++;
						}
					}
					// 내어 쓰기한다.
					if (nIndentType == 1) {
						for (i = 0;i < nIndent; i++) {
							*d++=' ';
							nDiff--;
							if (nType == 1) {
								acwidth++;
							} else {
								acwidth+=GetCharWidth(" ",1);
							}
						}
					}
				// 넘지 않았으면 문자 복사
				} else {
					if (IsDBCSLeadByte(*s)) {
						*d++=*s++;
					}
					*d++=*s++;
				}
			}
			if (s==src+ed-st) {
				break;
			}
		}
		break;
	case 3://문자열로 분리 (앞)
	case 4://문자열로 분리 (뒤)
		sp = s;
		for (;;) {
			ReallocBuf(dest,d,1024,2048);

			if(nType == 3){//앞에서 분리
				if(s >= sp && s <= (src + ed - st) - stLen){ //이전에 찾은 문자열 만큼 경과한 후부터 다시 비교
					if((bCase && !strncmp(s,szSplitText,stLen)) || (!bCase && !strnicmp(s,szSplitText,stLen))){
						sp = s + stLen;//찾았을 경우는 다음 위치로 헤드포인트 미리이동
						*d++='\r';
						*d++='\n';
						nDiff-=2;
						// 분리된 줄의 처음 공백 제거,공백포함 정확히 자르려면 제거옵션 off 해야함
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}

						
					}
				}
				if (IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;

				if(sp < s)//못찾았을 경우 savep가 현재 위치보다 작다.이때는 s와 동일한 위치를 가리키도록 한칸이동
					sp = s;
			}
			else{//뒤에서 분리
				if(IsDBCSLeadByte(*s))
					*d++=*s++;
				*d++=*s++;
				
				if(s >= sp + stLen){//찾는 문자열 보다 경과한 이후에

					ASSERT(s - stLen == sp);
					if((bCase && !strncmp(sp,szSplitText,stLen)) || (!bCase && !strnicmp(sp,szSplitText,stLen))){
						*d++='\r';
						*d++='\n';
						nDiff -= 2;
						// 분리된 다음줄 첫부분의 공백은 건너 뜀
						if (bRemoveSpace) {
							while (AeIsWhiteSpace(*s)) {
								s++;
								nDiff++;
							}
						}
						sp = s;
					}
					else{//우측으로 한칸이동
						if(IsDBCSLeadByte(*sp))
							sp++;
						sp++;
					}
				}
			}
			if (s >= src + ed-st)
				break;
		}
		break;

	}

	ENDARRANGEPARA(29)
}

//nOrient = 0 왼쪽, 1 = 가운데 ,2 = 오른 , nUnitType = 0 문자수 1 = 픽셀
void DETextCtrl::AlignPara(int nOrient, int nUnitType, int nUnitNum)
{
	BEFOREARRANGEPARA
	int acwidth,extra;
	int i;
	TCHAR *s2;

	for (;;) {
		acwidth = 0;
		// 앞쪽 공백은 건너뛴다.
		while (AeIsWhiteSpace(*s)) {
			s++;
			nDiff++;
		}
		s2=s;
		// 문단 끝까지 폭 계산
		for (;;) {
			if ((s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') || (s==src+ed-st)) {
				break;
			}
			if (nUnitType == 0) {
				if (IsDBCSLeadByte(*s)) {
					acwidth+=2;
					s++;
				} else {
					acwidth++;
				}
			} else {
				if (*s=='\t') {
					acwidth=(acwidth/m_cf.TabSize+1)*m_cf.TabSize;
				} else {
					if (IsDBCSLeadByte(*s)) {
						acwidth+=GetCharWidth(s,2);
						s++;
					} else {
						acwidth+=GetCharWidth(s,1);
					}
				}
			}
			s++;
		}
		// 기준폭보다 더 길면 그대로 복사
		if (acwidth >= nUnitNum || nOrient == 0) {
			for (;s2!=s;) {
				*d++=*s2++;
			}
		} else {
			ReallocBuf(dest,d,1024,2048);
			extra=(nUnitNum - acwidth);
			if (nUnitType == 1) {
				extra=extra/GetCharWidth(" ",1);
			}
			switch (nOrient) {
			case 1:
				// 중앙:여분 공백의 절반만 삽입
				for (i=0;i<extra/2;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			case 2:
				// 오른쪽:여분 공백 삽입 후 복사
				for (i=0;i<extra;i++) {
					*d++=' ';
					nDiff--;
				}
				break;
			}
			for (;s2!=s;) {
				*d++=*s2++;
			}
		}
		if (s==src+ed-st) {
			break;
		}
		// 문단 끝의 개행 코드 복사. 마지막 문단에는 이 개행 코드가 없음
		*d++=*s++;
		*d++=*s++;
	}

	ENDARRANGEPARA(30)
}

// 문단 크기순 정렬
void DETextCtrl::SortPara(int asc, BOOL Case, BOOL Unique)
{
	BEFOREARRANGEPARA
	struct stPara {
		TCHAR *ptr;			// 문단 시작 위치
		int len;			// 문단의 길이
		int order;			// 순서값
	};
	stPara *arPara;
	int nPara,i,j;
	TCHAR *p;
	int result,order;
	int same;

	// src에는 널 문자분, dest는 마지막 개행 코드분을 추가할당한다.
	s=src=(TCHAR *)realloc(src,ed-st+1);
	src[ed-st]=0;
	d=dest=(TCHAR *)realloc(dest,ed-st+2);

	// 문단 개수를 구하고 arPara를 할당한다.
	for (p=src,nPara=1;*p;p++) {
		if (*p=='\r' && *(p+1)=='\n') {
			nPara++;
			*p++=0;
			*p=0;
		}
	}
	arPara=(stPara *)malloc(nPara*sizeof(stPara));

	// 각 문단의 시작 위치와 길이를 구한다.
	for (i=0,p=src;i<nPara;i++) {
		arPara[i].ptr=p;
		arPara[i].len=lstrlen(p);
		p+=(arPara[i].len+2);
	}

	// 각 문단의 순서를 구한다.
	for (i=0;i<nPara;i++) {
		order=0;
		for (j=0;j<nPara;j++) {
			if (i == j) continue;
			if (Case) {
				result=strcmp(arPara[i].ptr,arPara[j].ptr);
			} else {
				result=strcmpi(arPara[i].ptr,arPara[j].ptr);
			}
			if (asc) {
				if (result < 0) order++;
			} else {
				if (result > 0) order++;
			}
		}
		arPara[i].order=order;
	}

	// 순서대로 dest로 복사한다. 같은 순위가 있을 수 있고 빠지는 순위도 있다.
	for (i=0;i<nPara;i++) {
		for (j=0,same=0;j<nPara;j++) {
			if (arPara[j].order == i) {
				same++;
				// 같은 순위가 둘 이상이고 중복 제거 옵션이 설정되어 있는 경우
				if (same > 1 && Unique) {
					nDiff+=(arPara[j].len+2);
				} else {
					memcpy(d,arPara[j].ptr,arPara[j].len);
					d+=arPara[j].len;
					*d++='\r';
					*d++='\n';
				}
			}
		}
	}
	// 마지막의 불필요한 개행 코드 제거
	d-=2;

	free(arPara);
	ENDARRANGEPARA(31)
}

//nType : 0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
//3 = 각줄을 nLine 만큼 증가,4 = 각줄을 nLine 만큼 감소
void DETextCtrl::ArrangeEmptyPara(int nType, int nLine)
{
	BEFOREARRANGEPARA
	int nEmpty,i;

	for (;;) {
		ReallocBuf(dest,d,1024,2048);
		// 개행 코드. 일단 복사 후 빈줄 수를 맞춤
		if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
			*d++=*s++;
			*d++=*s++;
			// 빈 줄 수 계산
			for (nEmpty=0;;) {
				while (AeIsWhiteSpace(*s)) {
					s++;
					nDiff++;
				}
				if (s[0]=='\r' && s+1 < src+ed-st && s[1]=='\n') {
					nEmpty++;
					s+=2;
					nDiff+=2;
				} else {
					break;
				}
			}
			
			// 빈줄수 계산
			//0=삽입 nLine 보다 작으면 nLine으로 만듬,1= nLine으로 픽스,2= nLine 이상은 삭제
			switch (nType) {
			case 0://최소 nLine으로 만듬,nLine보다 큰 줄은 냅둠
				i = max(nEmpty,nLine);
				break;
			case 1://nLine으로 fix,nLine = 0 이면 모든 공백줄삭제
				i = nLine;
				break;
			case 2://nLine 이상은 nLine 으로 만듬,nLine = 0 이면 모든 공백줄삭제
				i = min(nEmpty,nLine);
				break;
			case 3://각줄을 nLine 만큼 증가
				i = nEmpty + nLine;
				break;
			case 4://각줄을 nLine 만큼 제거
				i = nEmpty - nLine;
				break;
			}

			// 계산된 빈줄 수 삽입
			for (;i>0;i--) {
				*d++='\r';
				*d++='\n';
				nDiff-=2;
			}
		} else {
			if (IsDBCSLeadByte(*s)) {
				*d++=*s++;
			}
			*d++=*s++;
		}
		if (s==src+ed-st) {
			break;
		}
	}

	ENDARRANGEPARA(32)
}

//문서상의 offset 위치를 화면 중앙에 표시
void DETextCtrl::ArrangeVerticalCenter(int nPos)
{
	int x,y;

	GetXYFromOff(nPos,x,y);
	m_cf.yPos=max(0,((y-m_cf.frt.top)-(m_cf.frt.bottom-m_cf.frt.top)/2)/m_cf.LineHeight*m_cf.LineHeight);
	if (IsWindowEnabled(m_sbVert)) {
		SetScrollPos(m_sbVert, SB_CTL, m_cf.yPos, TRUE);
	}
	Invalidate(-1);
	SetCaret();
}

void DETextCtrl::GetParaText(int nPara,TCHAR *Text,int len)
{
	int ts,te;
	int i;
	TCHAR *p;

	ts=GetOffFromPara(nPara,0);
	te=m_cf.pLine[GetParaLastLine(nPara)].endoff;

	for (p=Text,i=ts;i<te;i++) {
		if (m_pEF->buf[i]=='\t') {
			*p++=' ';
			*p++=' ';
			*p++=' ';
			*p++=' ';
		} else {
			if (m_pEF->IsDBCS(i)) {
				*p++=m_pEF->buf[i++];
			}
			*p++=m_pEF->buf[i];
		}
		if (p-Text >= len-2) {
			break;
		}
	}
	*p=0;
}
