#include <CtrlLib/CtrlLib.h>
#include "UTLCtrl.h"
#define IMAGECLASS UTLImag
#define IMAGEFILE <UTLCtrl/UTLCtrl.iml>
//#include <Draw/iml_header.h>
//#include <Draw/iml_source.h>
#include <Draw/iml.h>

UTLCtrl::Node::Node()
{
	Init();
}

UTLCtrl::Node::Node(const Image& img, const Value& v)
{
	Init();
	image = img;
	key = value = v;
}

UTLCtrl::Node::Node(const Image& img, const Value& v, const Value& t)
{
	Init();
	image = img;
	key = v;
	value = t;
}

UTLCtrl::Node::Node(const Value& v)
{
	Init();
	key = value = v;
}

UTLCtrl::Node::Node(const Value& v, const Value& t)
{
	Init();
	key = v;
	value = t;
}



UTLCtrl::UTLCtrl()
{
	levelcx = 16;
	rowHeight = 32;
	colCnt=1;
	colWidth.Add(180);
	colTitle.Add("Tree");
	nocursor = false;
//	Col=1;
	dragPtx=-10;//
	dragCol=-1;//which col is dragging
	isdrag=false;//Is dragging column line
	RMargin=30;//Margin at right side of the table,by Ulti
	dirty = true;
	isselection = false;
	multiselect = false;
	Clear();
	SetFrame(ViewFrame());
	AddFrame(sb);
	sb.WhenScroll = THISBACK(Scroll);
	BackPaint();//Add this to avoid flicker,very useful
}

UTLCtrl::~UTLCtrl() {}
//此处之前均可理解
void   UTLCtrl::Layout()
{
	sb.SetPage(GetSize());
	sb.SetLine(rowHeight);
}

Size   UTLCtrl::Item::GetValueSize() const
{
	if(IsNull(size))
	  return display ? display->GetStdSize(value) : StdDisplay().GetStdSize(value);
	else
	  return size;
}

Size   UTLCtrl::Item::GetSize() const
{
	Size sz = GetValueSize();
	sz += Size(2 * margin, 2 * margin);
	Size isz = image.GetSize();
	sz.cx += isz.cx;
	sz.cy = max(sz.cy, isz.cy);
	return sz;
}

void   UTLCtrl::SetRoot(const UTLCtrl::Node& n)
{
	(UTLCtrl::Node &)item[0] = n;
	RefreshItem(0);
}

void   UTLCtrl::SetRoot(const Image& img, Value v)
{
	SetRoot(UTLCtrl::Node(img, v).CanOpen());
}

void   UTLCtrl::SetRoot(const Image& img, Value v, Value t)
{
	SetRoot(UTLCtrl::Node(img, v, t).CanOpen());
}

int    UTLCtrl::Insert(int parentid, int i, const UTLCtrl::Node& n)//新入节点在父亲的孩子节点中的位置
{
	int id;
	if(freelist >= 0) {   //首先看item数组是否有空闲位置,如有,新插入的Node放在该位置
		id = freelist;
		freelist = item[id].freelink;
	}
	else { //如果没有,就新加一个位置
		id = item.GetCount();
		item.Add();
	}
	Item& m = item[id];
	m.parent = parentid;
	(UTLCtrl::Node&)m = n;
	item[id].subItemText.SetCount(colCnt-1);
	if(parentid >= 0) {
		Item& parent = item[parentid];
		parent.child.Insert(i, id);
	}
	dirty = true;
	Dirty(parentid);
	return id;
}//此routine不难理解

int    UTLCtrl::Add(int parentid, const UTLCtrl::Node& n)
{
	return Insert(parentid, item[parentid].child.GetCount(), n);
}

int    UTLCtrl::Insert(int parentid, int i)
{
	return Insert(parentid, i, UTLCtrl::Node());
}

int    UTLCtrl::Add(int parentid)
{
	return Add(parentid, UTLCtrl::Node());
}

int    UTLCtrl::Insert(int parentid, int i, const Image& img, Value v, bool withopen)
{
	return Insert(parentid, i, UTLCtrl::Node(img, v).CanOpen(withopen));
}

int    UTLCtrl::Insert(int parentid, int i, const Image& img, Value v, Value t, bool withopen)
{
	return Insert(parentid, i, UTLCtrl::Node(img, v, t).CanOpen(withopen));
}

int    UTLCtrl::Add(int parentid, const Image& img, Value v, bool withopen)
{
	return Add(parentid, UTLCtrl::Node(img, v).CanOpen(withopen));
}

int    UTLCtrl::Add(int parentid, const Image& img, Value v, Value t, bool withopen)
{
	return Add(parentid, UTLCtrl::Node(img, v, t).CanOpen(withopen));
}


Value  UTLCtrl::Get(int id) const //Get返回的是KEY
{
	const Item& m = item[id];
	return m.key;
}

Value  UTLCtrl::GetValue(int id) const //GetValue才返回值
{
	const Item& m = item[id];
	return m.value;
}

void  UTLCtrl::Set(int id, Value v) //设置KEY的值
{
	Item& m = item[id];
	m.value = m.key = v;
	RefreshItem(id);
}

void  UTLCtrl::Set(int id, Value k, Value v) //设置KEY和值
{
	Item& m = item[id];
    m.key = k;
    m.value = v;
	RefreshItem(id);
}

void   UTLCtrl::SetNode(int id, const UTLCtrl::Node& n)//设置节点
{
	(UTLCtrl::Node&)item[id] = n;
	Dirty(id);
}

void   UTLCtrl::RemoveChildren(int id)//删除id的孩子节点,不难理解
{
	Item& m = item[id];
	for(int i = 0; i < m.child.GetCount(); i++)
		RemoveSubtree(m.child[i]);
	m.child.Clear();
	Dirty(id);
}

void   UTLCtrl::RemoveSubtree(int id)//删除id极其子节点,未处理其在父节点中的信息
{
	Item& m = item[id];
	if(m.linei == cursor)
		cursor = item[m.parent].linei;//先把光标移到父节点
	m.value = Null;
	m.image = Null;
	for(int i=0;i<colCnt-1;i++)
		m.subItemText[i]="";
	RemoveChildren(id);//删除其孩子节点
	m.freelink = freelist;//该内存位置加到空闲列表
	freelist = id;
}

void   UTLCtrl::Remove(int id)//删除id极其子节点,同时删除其在父节点中的信息
{
	ASSERT(id > 0);
	int pi = item[id].parent;
	Item& parent = item[item[id].parent];
	parent.child.Remove(FindIndex(parent.child, id));//删除其在父亲中的信息
	RemoveSubtree(id);
	Dirty(pi);
}

void   UTLCtrl::Clear()//清除全部,重置为空,加item[0]
{
	item.Clear();
	item.Add();
	item[0].linei = -1;
	item[0].parent = -1;
	freelist = -1;
	Dirty();
	cursor = -1;
}


// revised version by Ulti,used only for fixed height rows treelist
void UTLCtrl::ReLine(int itemi, int level)
{
	int ii = line.GetCount();
	Item& m = item[itemi];
	  Line& l = line.Add();
	  l.level = level;
	  l.itemi = itemi;
      l.ll = -1;

	m.linei = ii;
	level++;

	if(m.isopen)
	{
	     for(int i = 0; i < m.child.GetCount(); i++)
		 {
			line[ii].ll = line.GetCount();
			ReLine(m.child[i], level);
		 }
	}
}

//revised version by Ulti,used only for fixed height rows treelist
void UTLCtrl::SyncTree()//同步树
{
	if(!dirty)//没有更新,不需同步
		return;
	//if(noroot)
		Open(0);
	int cursorid = GetCursor();
	for(int i = 0; i < item.GetCount(); i++)
		item[i].linei = -1;
	line.Clear();//行与项的关联重置
	ReLine(0, -1);
	Size treesize = GetSize();//treesize置0
	if(GetWidth()+RMargin<treesize.cx&&GetWidth()>0)
	{
		float ratio=((float)(treesize.cx-RMargin))/((float)GetWidth());
		for(int n=0;n<colCnt;n++)
			colWidth[n]=(int)colWidth[n]*ratio;
	}
	//treesize.cy=(line.GetCount()+1)*rowHeight;
	//treesize.cx=GetWidth()+rowHeight;
	//sb.SetTotal(treesize);//这里是让滚动条工作的关键
    SetSBSize();
	cursor = -1;
	dirty = false;
	if(cursorid >= 0)
		SetCursor(cursorid, false);
	Refresh();
}

bool UTLCtrl::IsOpen(int id) const//是否打开
{
	return item[id].isopen;
}

void UTLCtrl::Dirty(int id)
{
	ClearSelection();
	Size sz = GetSize();
	dirty = true;
	while(id >= 0) {
		int q = item[id].linei;
		if(q >= 0) {
			int y = q*rowHeight+(rowHeight>>1)- sb.GetY();//revised by Ulti
			Refresh(0, y, sz.cx, sz.cy - y);
			return;
		}
		id = item[id].parent;
	}
	Refresh();
}

void UTLCtrl::Open(int id, bool open)
{
	Item& m = item[id];
	if(m.isopen != open) {
		m.isopen = open;
		int q = GetCursor();
		while(q >= 0) {
			if(q == id) {
				SetCursor(id);
				break;
			}
			q = GetParent(q);
		}
		Dirty(id);
		if(open)
			WhenOpen(id);
		else
			WhenClose(id);
	}
}

void UTLCtrl::OpenDeep(int id, bool open)
{
	Open(id);
	Item& m = item[id];
	for(int i = 0; i < m.child.GetCount(); i++)
		OpenDeep(m.child[i], open);
}

void UTLCtrl::MakeVisible(int id)
{
	id = GetParent(id);
	while(id >= 0) {
		Open(id);
		id = GetParent(id);
	}
}

int UTLCtrl::FindLine(int y) const
{
	int l=y/rowHeight;
	return l> 0 ? l : 0;//这里需要再研究一下
}

int UTLCtrl::FindCol()
{
	int i;
	for(i=1;i<colCnt;i++)
	{
	  if(GetWidth(i)-sb.GetX()>colWidth[0]+(colWidth[i]-4)) break;
	}
	return i==colCnt?0:i;
}
void UTLCtrl::RefreshLine(int i)
{
	SyncTree();
	if(i >= 1&&i<line.GetCount()) {
		Size sz = GetSize();
		int y = i*rowHeight-sb.GetY();//revised by Ulti
		Refresh(0, y, sz.cx,rowHeight);
	}
}

void UTLCtrl::RefreshItem(int id)
{
	SyncTree();
	RefreshLine(item[id].linei);
}

int  UTLCtrl::GetItemAtLine(int i)
{
	SyncTree();
	return line[i].itemi;
}

int  UTLCtrl::GetLineAtItem(int id)
{
	SyncTree();
	return item[id].linei;
}

int  UTLCtrl::GetLineCount()
{
	SyncTree();
	return line.GetCount();
}

void UTLCtrl::SetCursorLine(int i, bool sc)
{
	if(nocursor)
		return;
	if(i != cursor) {
		i = minmax(i, 0, line.GetCount() - 1);
		if(i < 0) return;
		Item& m = item[line[i].itemi];
		if(sc)
			sb.ScrollIntoY(i*rowHeight, rowHeight);//revised by Ulti
		RefreshLine(cursor);
		cursor = i;
		RefreshLine(cursor);
		WhenCursor();
	}
}

void UTLCtrl::SetCursorLine(int i)
{
	SetCursorLine(i, true);
}

void UTLCtrl::SetCursorLineSync(int i)
{
	if(nocursor)
		return;
	if(i != cursor) {
		if(cursor < 0)
			Refresh();
		RefreshLine(cursor);
		if(i < 0)
			cursor = -1;
		else
			cursor = minmax(i,1, line.GetCount() - 1);
		RefreshLine(cursor);
		Item& m = item[line[cursor].itemi];
		if(cursor < 0)
			Refresh();
		else {
			Sync();
			sb.ScrollIntoY(cursor*rowHeight, rowHeight);//revised by Ulti
		}
		SetFocus();
		WhenCursor();
	}
}

void UTLCtrl::KillCursor()
{
	RefreshLine(cursor);
	cursor = -1;
	Refresh();
	WhenCursor();
}

void UTLCtrl::SetCursor(int id, bool sc)
{
	while(id > 0) {
		ASSERT(id >= 0 && id < item.GetCount());
		MakeVisible(id);
		SyncTree();
		const Item& m = item[id];
		if(m.linei >= 0) {
			SetCursorLine(m.linei, sc);
			return;
		}
		id = m.parent;
	}
	SetCursorLine(0, sc);
}

void UTLCtrl::SetCursor(int id)
{
	SetCursor(id, true);
}

int  UTLCtrl::GetCursor() const
{
	return cursor >= 0 ? line[cursor].itemi : -1;
}

Value  UTLCtrl::Get() const
{
	return IsCursor() ? Get(GetCursor()) : Value();
}

Value  UTLCtrl::GetValue() const
{
	return IsCursor() ? GetValue(GetCursor()) : Value();
}

int    UTLCtrl::Find(Value key)
{
	for(int i = 0; i < item.GetCount(); i++)
		if(Get(i) == key)
			return i;
	return -1;
}

bool   UTLCtrl::FindSetCursor(Value key)
{
	int q = Find(key);
	if(q < 0)
		return false;
	SetCursor(q);
	return true;
}

void UTLCtrl::ShiftSelect(int l1, int l2)
{
	if(!multiselect)
		return;
	bool b = false;
	if(l1 > l2)
		Swap(l1, l2);
	for(int i = l1; i <= l2; i++)
		SelectOne(line[i].itemi, true);
	UpdateSelect();
}

void UTLCtrl::LeftDown(Point p, dword flags)
{
	Point org = sb;

    if(p.y<0||p.y>-org.y+(line.GetCount())*rowHeight||p.x>GetActureWidth(colCnt-1))return;
    if(p.y<=rowHeight)
    {
        if(ShowDragArrow(p)) SetCapture();
    }
    else
    {
 	   int i = FindLine(p.y + org.y);
	   const Line& l = line[i];
	   int x = levelcx + l.level * levelcx - (levelcx >> 1);

	   if(p.x > x - 5 && p.x < x + 5)
		   Open(l.itemi, !IsOpen(l.itemi));
	   else {//后面的选择太慢,需要检查
		    SetFocus();
		     int q = cursor;
		     SetCursorLine(i);
		     if(cursor != q)
			 WhenAction();
		     if(multiselect)
		     {
			   if(flags & K_CTRL)
			   {
				 int id = GetCursor();
				 SelectOne(id, !IsSelected(id));
			   }
			   else {
				ClearSelection();
				if(flags & K_SHIFT) {
					ShiftSelect(q, cursor);
					cursor = q;}}
		       }
	         }
    }
}

void UTLCtrl::LeftDouble(Point p, dword flags)
{
	Point org = sb;
	if(p.y + org.y > sb.GetTotal().cy)
		return;
	if(FindLine(p.y + org.y) == GetCursorLine())
		WhenLeftDouble();
}

void UTLCtrl::RightDown(Point p, dword flags)
{
	Point org = sb;
	if(p.y + org.y < sb.GetTotal().cy) {
		int i = FindLine(p.y + org.y);
		if(i >= 0) {
			SetFocus();
			SetCursorLine(i);
		}
	}
	if(WhenBar)
		MenuBar::Execute(WhenBar);
}

void UTLCtrl::Paint(Draw& w)
{
	SyncTree();
	Size sz = GetSize();
	Point org = sb;
	scroller.Set(org);
	w.DrawRect(sz, SColorPaper);


	w.DrawRect(0,rowHeight-org.y,colWidth[0],(line.GetCount()-1)*rowHeight,SWhiteGray());


	int levelcx2 = levelcx >> 1;
	int halfRow = rowHeight >> 1;
	for(int i = 0; i < line.GetCount(); i++) {
		Line& l = line[i];
		if(l.ll >= 0) {
			int yl = i*rowHeight+halfRow - org.y;
			int yh = l.ll*rowHeight+halfRow - org.y;
			if(yh >= 0 && yl < sz.cy) {
				int x = levelcx + levelcx * l.level + levelcx2;
				w.DrawRect(x, yl, 1, yh - yl, SGreen()/*SBlack()/*SColorShadow*/);
			}
		}
	}//this part done


    int Col=FindCol();

	for(int i = FindLine(org.y+rowHeight); i < line.GetCount(); i++) {
		Line& l = line[i];
		w.DrawRect(0,-org.y+(i+1)*rowHeight,GetActureWidth(colCnt-1),1,SLtGray());//by Ulti,for test
		const Item& m = item[l.itemi];
		const Display *d = m.display;
		if(!d)
			d = &StdDisplay();
		Size msz = m.GetSize();
		Size isz = m.image.GetSize();
		Size vsz = m.GetValueSize();
		int y = i*rowHeight+halfRow- org.y;//let the tree item is in the middle of a row
		if(y > sz.cy)//do not draw things out of range
			break;
		if(w.IsPainting(0, y-halfRow,sz.cx,rowHeight )) {
			int x = 0;
			x = levelcx + l.level * levelcx;
			Point op = Point(x - levelcx2, y );//draw horiz lines
			w.DrawRect(op.x, op.y, levelcx2, 1,SGreen() /*SBlack()/*SColorShadow*/);
			if(m.canopen || m.child.GetCount()) {
				Image im = m.isopen ? /*CtrlImg::treeminus() : CtrlImg::treeplus()*/UTLImag::treeexpend():UTLImag::treecollapse();
				op -= im.GetSize() / 2;
				w.DrawImage(op.x, op.y, im);
			}
			w.DrawImage(x, y - isz.cy / 2, m.image);
			x += isz.cx;
			dword st = 0;
			Color fg = SColorText;
			Color bg = SWhiteGray()/*SColorPaper*/;
			Color tbg=SColorPaper;
			Color tfg = SColorText;
			bool hasfocus = HasFocus();
			if(IsReadOnly())
				st |= Display::READONLY;
			if(m.sel) {
				st |= Display::SELECT;
				fg = hasfocus ? SColorMark() : SColorText;
				tfg = hasfocus ? SColorHighlightText : SColorText;
				//bg = hasfocus ? SColorHighlight : SColorFace;
				tbg = hasfocus ? SColorHighlight : SColorPaper;;
			}
			if(i == cursor && !nocursor) {
				st |= Display::CURSOR;
				fg = hasfocus ? SColorMark() : SColorText;
				tfg = hasfocus ? SColorHighlightText : SColorText;
				//bg = hasfocus ? (isselection ? Blend(SColorLight, SColorHighlight) : SColorHighlight)
				//              : SColorFace;
				tbg = hasfocus?(isselection ? Blend(SColorLight, SColorHighlight) : SColorHighlight)
				              : SColorPaper;
			}
			if(hasfocus) st |= Display::FOCUS;

			w.DrawRect(x, y, vsz.cx + 2 * m.margin, msz.cy, bg);
			d->Paint(w, RectC(x + m.margin, y - vsz.cy / 2, vsz.cx, vsz.cy), m.value,fg, bg, st);


			if(Col!=0)
			{
			  int cellx=colWidth[0];
		      for(int j=Col;j<colCnt;j++)
		     {
		        cellx+=colWidth[j];
		        d->Paint(w,Rect(cellx-colWidth[j]+1,i*rowHeight+1-org.y,cellx-1,(i+1)*rowHeight-1-org.y),
		                 m.subItemText[j-1],tfg,tbg,st);
		     }
			}
		}

	}
	w.DrawRect(0,0,GetActureWidth(colCnt-1),rowHeight,SColorFace);//title row
	w.DrawRect(0,rowHeight,GetActureWidth(colCnt-1),1,SLtGray());//by Ulti,for test
	w.DrawRect(colWidth[0],-org.y,1,line.GetCount()*rowHeight,SLtGray());//just for test
	const Display *dd;
	dd = &StdDisplay();

	dd->Paint(w,Rect(1,0,colWidth[0]-1,rowHeight),colTitle[0],SColorText,SColorFace,0);//first cell in title row
	if(Col!=0)
	{
 	  int lx=colWidth[0];
	  for(int i=FindCol();i<colCnt;i++)
	  {
	    lx+=colWidth[i];
	    w.DrawRect(/*GetWidth(i)-org.x*/lx,-org.y,1,line.GetCount()*rowHeight,SLtGray());//just for test
	    dd->Paint(w,Rect(lx-colWidth[i]+1,0,lx-1,rowHeight),colTitle[i],SColorText,SColorFace,0);
	  }
	}
	w.DrawRect(Rect(GetActureWidth(colCnt-1)+1,0,sz.cx,line.GetCount()*rowHeight-org.y),SColorPaper);
    if(isdrag){w.DrawRect(dragPtx,0,1,sz.cy,SColorHighlight());isdrag=false;}
}

void UTLCtrl::Scroll()
{
	SyncTree();
	scroller.Scroll(*this, sb);
	Refresh();
}

void UTLCtrl::MouseWheel(Point, int zdelta, dword)
{
	sb.WheelY(zdelta);
}

void UTLCtrl::ChildGotFocus()
{
	for(int i = 0; i < line.GetCount(); i++) {
		Item& m = item[line[i].itemi];
	}
}

bool UTLCtrl::Tab(int d)
{
	if(cursor < 0)
		return false;
	Item& m = item[line[cursor].itemi];

	int i = cursor;
	for(int i = cursor + d; i >= 0 && i < line.GetCount(); i += d) {
		Item& m = item[line[i].itemi];
	}
	return false;
}

bool UTLCtrl::Key(dword key, int)
{
	SyncTree();
	Size sz = GetSize();
	int cid = GetCursor();
	bool shift = key & K_SHIFT;
	key &= ~K_SHIFT;
	switch(key) {
	case K_TAB:
		return Tab(1);
	case K_SHIFT_TAB:
		return Tab(-1);
	case K_UP:
		SetCursorLineSync(cursor > 1 ? cursor - 1 : 1);
		break;
	case K_DOWN:
		SetCursorLineSync(cursor >= 1 ? cursor + 1 : line.GetCount() - 1);
		break;
	case K_PAGEDOWN:
		SetCursorLineSync(cursor >= 1 ? FindLine(cursor*rowHeight+1+ sz.cy) : line.GetCount() - 1);
		break;
	case K_PAGEUP:
		SetCursorLineSync(cursor >= 1? FindLine(cursor*rowHeight+1- sz.cy) : 1);
		break;
	case K_LEFT:
		if(cid >= 0)
			Close(cid);
		break;
	case K_RIGHT:
		if(cid >= 0)
			Open(cid);
		break;
	default:
		return false;
	}
	if(cid != cursor)
		if(shift && multiselect)
			ShiftSelect(cid, cursor);
		else
			ClearSelection();
	if(cursor != cid)
		WhenAction();
	return true;
}

void UTLCtrl::GotFocus()
{
	if(dirty)
		return;
	RefreshLine(cursor);
}

void UTLCtrl::LostFocus()
{
	if(dirty)
		return;
	RefreshLine(cursor);
}

void UTLCtrl::ChildRemoved(Ctrl *)
{
	Dirty();
}

void  UTLCtrl::SetData(const Value& data)
{
	FindSetCursor(data);
}

Value UTLCtrl::GetData() const
{
	return Get();
}

Point  UTLCtrl::GetScroll() const
{
	return sb;
}

void UTLCtrl::ScrollTo(Point sc)
{
	sb = sc;
}

void UTLCtrl::ClearSelTree(int id)
{
	Item& m = item[id];
	m.sel = false;
	for(int i = 0; i < m.child.GetCount(); i++)
		ClearSelTree(m.child[i]);
}

void UTLCtrl::ClearSelection()
{
	if(isselection) {
		ClearSelTree(0);
		isselection = false;
		WhenSelection();
		WhenAction();
		Refresh();
	}
}

bool UTLCtrl::UpdateSelTree(int id)
{
	Item& m = item[id];
	if(m.sel)
		return true;
	for(int i = 0; i < m.child.GetCount(); i++)
		if(UpdateSelTree(m.child[i]))
			return true;
	return false;
}

void UTLCtrl::UpdateSelect()
{
	isselection = UpdateSelTree(0);
	WhenSelection();
	WhenAction();
}

void UTLCtrl::SelectOne(int id, bool sel)
{
	if(!multiselect) {
		ClearSelection();
		return;
	}
	if(item[id].canselect)
		item[id].sel = sel;
	UpdateSelect();
	RefreshItem(id);
}

void UTLCtrl::MouseMove(Point p, dword keyflags) {//deal with col drag
  if(!HasCapture())
  {
     for(int i=0;i<colCnt;i++)
     if(p.x>GetActureWidth(i)-2&&p.x<GetActureWidth(i)+2&&p.y>0&&p.y<rowHeight)
     {
       dragPtx=p.x;
       dragCol=i;
       break;
     }
  }
  else
  {
      if(dragCol==-1) return;
      Size sz;
      sz=GetSize();
      if(p.x>sz.cx-10) dragPtx=sz.cx-10;
       else
           if(p.x<GetActureWidth(dragCol)-colWidth[dragCol]+5)
             dragPtx=GetActureWidth(dragCol)-colWidth[dragCol]+5;
             else dragPtx=p.x;
      isdrag=true;
      if(dragCol>0)colWidth[dragCol]+=(dragPtx-GetActureWidth(dragCol));
      if(dragCol==0) colWidth[0]=dragPtx;
  }
  Refresh();
}

void UTLCtrl::LeftUp(Point p, dword keyflags) {//release left button
    SetSBSize();
	Refresh(dragPtx-2,0,4,GetSize().cy);
}
void UTLCtrl::MouseLeave()
{
  Refresh();
}

Image UTLCtrl::CursorImage(Point p, dword keyflags) {//show cursor
    return ShowDragArrow(p)?Image::SizeHorz():Image::Arrow();
}

int UTLCtrl::GetWidth()//get sum of col width
{
	return GetWidth(colCnt-1);
}
int UTLCtrl::GetWidth(int col)//get sum of colwith(col 0~col)
{
	int w=0;
	for(int i=0;i<=col;i++) w+=colWidth[i];
	return w;
}

int UTLCtrl::GetActureWidth(int col)//get col display width(col 0~col,some of cols not displayed)
{
	if(col<0||col>=colCnt) return -10;
	int Col=FindCol();
	int w=colWidth[0];
	if(col==0||col<Col||Col==0) return w;
	for(int i=Col;i<=col;i++) w+=colWidth[i];
	return w;
}

void UTLCtrl::SetColCount(int cnt)//set column count
{
	if(cnt<2||cnt>100){ PromptOK("Range exceed!");return;}

	Size sz=GetSize();
	for(int i=1;i<cnt;i++)
	{
		colWidth.Add((sz.cx-colWidth[0])/(cnt-1)>50?(sz.cx-colWidth[0])/(cnt-1):50);
		colTitle.Add("");
	}
	colCnt=cnt;
}

void UTLCtrl::SetColWidth(int col,int width)//set width of one of col
{
	if(col<0||col>colCnt-1) return;
	colWidth[col]=width>20?width:20;
}

void UTLCtrl::SetTitle(int col,String title)//set column title
{
	if(col<0||col>=colCnt) return;
	colTitle[col]=title;
}

void UTLCtrl::SetSubText(int id,int sub,String txt)//set tree subitem text
{
	if(sub<0||sub>=colCnt-1)return;
	item[id].subItemText[sub]=txt;
}

bool UTLCtrl::ShowDragArrow(Point p)//is that show drag cursor?
{
   return (p.x>dragPtx-2&&p.x<dragPtx+2)?true:false;
}

void UTLCtrl::SetSBSize()//set scroller total size,called when syntree and and when you drag column width
{
	Size size;
    size.cy=(line.GetCount()+1)*rowHeight;

	size.cx=GetWidth()+RMargin;
	sb.SetTotal(size);//这里是让滚动条工作的关键
}

int UTLCtrl::GetLineLevel(int i)
{
	return (i>0&&i<line.GetCount())?line[i].level:-1;
}

int UTLCtrl::GetLevel(int id)
{
	SyncTree();
	return line[item[id].linei].level;
}