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

1999 ~ 2000 ABCProject started.
2009/10/09  ABCWTL + SDK DLL Project Restart.
            ABCConvert MFC Project to KFC Platform with my KFC Library
            ABCRenewal and Rebuild all architecture.
            ABC----------------------------------------------------------
2010/03/20  ABCKRKIM   버그픽스:쓰레드에서 검색시 GetFocus NULL로 인한 캐럿위치 오작동.
            ABC        DE_BUGFIX_THREADSAFE_GETFOCUS_INPUT
            ABC        검색창,간편검색바에서 메인창 단축키 가능하게 함.
            ABC        F3등 다음찾기시 간편검색바에 포커스있으면 우선검색어로 사용하고
                     검색창이 떠있으면 현재 입력된 검색어로 사용하고 그것도 아니면 이전검색어로 검색함.
                     검색창에서 F3등시 찾았으면 본문에 포커스주고 못찾았으면 그대로 유지.
                     검색창에서 다음찾기 버튼으로 했을 경우는 찾았어도 포커스를 검색창에 그대로 유지하게 함.
#include "stdafx.h"
#include "DEStructs.h"
#include ".h"
#include "langs.h"
 AE
//////////////////////////////////////////////////////////////////////////////////////////////////
::()
{
	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 ::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,"",NULL, dwStyle/*WS_OVERLAPPEDWINDOW*/,
		/*CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,*/
		x,y,w,h,hParent,(HMENU)id,NULL);
	return TRUE;
}

//KFC >>
BOOL 검색 쓰레드 종료
::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 ::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 ::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 ::OnClose()
{
	return 0;
}

void ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::OnCancelMode()
{
	m_cf.bCapture=FALSE;
}

//<<KFC

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

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

LRESULT ::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 ::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 ::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 ::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 ::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;
