#include "CtrlLib.h"

namespace Upp {

CH_VALUE(TreeDropEdge, ChBorder(BlackBorder()));

CtrlFrame& TreeDropFrame()
{
	static LookFrame m(TreeDropEdge);
	return m;
}

PopUpTree::PopUpTree() {
	SetFrame(TreeDropFrame());
	Accel();
	MouseMoveCursor();
	NoPopUpEx();
	SetDropLines(16);
	open = autosize = false;
	showpos = Null;
	WhenOpen = WhenClose = THISBACK(OpenClose);
}

PopUpTree::~PopUpTree() {}

void PopUpTree::CancelMode() {
	if(open) {
		DoClose();
		WhenCancel();
	}
	TreeCtrl::CancelMode();
}

void PopUpTree::DoClose() {
	open = false;
	Ctrl::Close();
}

void PopUpTree::Deactivate() {
	if(open) {
		DoClose();
		IgnoreMouseClick();
		WhenCancel();
	}
}

void PopUpTree::Select() {
	if(IsCursor() && !GetData().IsVoid()) {
		DoClose();
		WhenSelect();
	}
}

bool PopUpTree::Key(dword key, int n) {
	switch(key) {
	case K_ENTER:
	case K_ALT_DOWN:
		DoClose();
		WhenSelect();
		return true;
	case K_ESCAPE:
		DoClose();
		WhenCancel();
		return true;
	}
	return TreeCtrl::Key(key, n);
}

void PopUpTree::PopUp(Ctrl *owner, int x, int top, int bottom, int width) {
	DoClose();
	Rect area = Ctrl::GetWorkArea();
	int mh = min(maxheight, area.bottom - bottom);
	int h = AddFrameSize(width, maxheight).cy;
	showpos.x = x;
	showpos.y = bottom;
	showwidth = width;
	up = false;
	if(showpos.y + h > area.bottom) {
		up = true;
		showpos.y = top;
	}
	open = false;

	int ht = AddFrameSize(width, min(mh, autosize ? GetTreeSize().cy : INT_MAX)).cy;
	Rect rt = RectC(showpos.x, showpos.y - (up ? ht : 0), showwidth, ht);
	if(GUI_PopUpEffect()) {
		bool vis = sb.x.IsShown();
		bool ah = sb.x.IsAutoHide();
		sb.AutoHide(false);
		sb.Hide();
		sPaintRedirectCtrl pb;
		pb.ctrl = this;
		if(up) {
			SetRect(Rect(rt.left, rt.bottom - 1, rt.right, rt.bottom));
			Ctrl::Add(pb.TopPos(0, rt.Height()).LeftPos(0, rt.Width()));
		}
		else {
			SetRect(Rect(rt.left, rt.top, rt.right, rt.top + 1));
			Ctrl::Add(pb.BottomPos(0, rt.Height()).LeftPos(0, rt.Width()));
		}
		CenterCursor();
		Ctrl::PopUp(owner, true, true, GUI_DropShadows());
		SetFocus();
		Ctrl::ProcessEvents();
		Animate(*this, rt, GUIEFFECT_SLIDE);
		Ctrl::Remove();
		sb.Show(vis);
		sb.AutoHide(ah);
		pb.Remove();
		open = true;
	}

	CenterCursor();
	SetRect(rt);
	if(!open)
		Ctrl::PopUp(owner, true, true, GUI_DropShadows());
	SetFocus();
	open = true;
}

void PopUpTree::OpenClose(int)
{
	if(autosize) {
		SyncTree();
		Rect area = Ctrl::GetWorkArea();
		int mh = min(maxheight, area.bottom - showpos.y);
		int ht = AddFrameSize(showwidth, min(mh, GetTreeSize().cy)).cy;
		SetRect(RectC(showpos.x, showpos.y - (up ? ht : 0), showwidth, ht));
	}
}

void PopUpTree::PopUp(Ctrl *owner, int width)
{
	Rect r = owner->GetScreenRect();
	r.right = r.left + width;
	PopUp(owner, r.left, r.top, r.bottom, width);
	if(IsNull(showpos))
		showpos = r.TopLeft();
	OpenClose(0);
}

void PopUpTree::PopUp(Ctrl *owner)
{
	Rect r = owner->GetScreenRect();
	PopUp(owner, r.left, r.top, r.bottom, r.Width());
}

void DropTree::Sync() {
	Image icon;
	if(tree.IsCursor())
		icon = tree.GetNode(tree.GetCursor()).image;
	icond.Set(valuedisplay ? *valuedisplay : tree.GetDisplay(tree.GetCursor()), icon);
	MultiButton::SetDisplay(icond);
	Set(tree.GetValue());
}

bool DropTree::Key(dword k, int) {
	if(IsReadOnly()) return false;
	if(k == K_ALT_DOWN) {
		Drop();
		return true;
	}
	return false;
}

void DropTree::Drop() {
	if(IsReadOnly()) return;
	if(dropfocus)
		SetFocus();
	WhenDrop();
	tree.PopUp(this, GetRect().GetWidth());
}

void DropTree::Select() {
	if(dropfocus)
		SetFocus();
	Sync();
	UpdateAction();
}

void DropTree::Cancel() {
	if(dropfocus)
		SetFocus();
	Sync();
}

void DropTree::Clear() {
	tree.Clear();
	tree <<= Null;
	Sync();
	Update();
}

void DropTree::SetData(const Value& data)
{
	if(tree.Get() != data) {
		tree <<= data;
		Update();
		Sync();
	}
}

Value DropTree::GetData() const
{
	return notnull && IsNull(tree.Get()) ? NotNullError() : tree.Get();
}

DropTree& DropTree::ValueDisplay(const Display& d)
{
	valuedisplay = &d;
	Sync();
	return *this;
}

DropTree::DropTree()
{
	valuedisplay = NULL;
	dropfocus = false;
	notnull = false;
	AddButton().Main().WhenPush = THISBACK(Drop);
	NoInitFocus();
	tree.WhenSelect = THISBACK(Select);
	tree.WhenCancel = THISBACK(Cancel);
	dropwidth = 0;
}

};
