#include "CtrlMover.h"

//returns the offset of a ctrl's drawing area w.r.t. its parent's drawing area
void CtrlMover::GetOffset(const Ctrl& c, Point& p)
{
	p += c.GetRect().TopLeft();
	if(c.InView())
		p += c.GetParent()->GetView().TopLeft();
}

//returns the offset of a ctrl's drawing area w.r.t an upper parent's drawing area.
void CtrlMover::GetOffset(const Ctrl& c, const Ctrl& q, Point& p)
{
	if(&c == &q) return;
	GetOffset(c, p);
	if(Ctrl* pc = c.GetParent())
		GetOffset(*pc, q, p);
}

//calculate topleft offset of c w.r. up to par recursively
Point CtrlMover::GetOffset(const Ctrl& c, const Ctrl& q)
{
	Point p; p.Clear();
	GetOffset(c, q, p);
	return p;
}

void CtrlMover::OnCtrlLeft(Ctrl& c, Point p, dword keyflags)
{
	if(c.InFrame()) return; //may not move frames
	rc.Remove();
	if(&c == &rc) return;
	if(&c == pctrl) return; //mat not move base
	UpdateAction();
}

void CtrlMover::OnRectChange()
{
	if(!pctrl || !ctrl) { rc.Remove(); return; }

	Rect r = rc.GetData();
	r.Offset(-GetOffset(*ctrl, *pctrl) + ctrl->GetRect().TopLeft());
	
	ctrl->SetRect(r);
	Action();
}

void CtrlMover::OnMissed(Point p, dword keyflags)
{
	CtrlFinder::LeftDown(p, keyflags);
}

void CtrlMover::Updated()
{
	CtrlFinder::Updated();

	if(!pctrl || !ctrl) { rc.Remove(); return; }

	Add(rc.SizePos());

	//if c is frame: rect in parents window, 
	//if is in view, then rect in view area, which itself is subarea of parent
	//using only GetOffset we wouldnt be able to get the rect, only the offset point
	//but we do not need the offset of the drawing area, but the offesstet drawing area itself
	//thats why ctrl->GetParent, it replics part of GetOffset
	//revert the GetRect.TopLeft offset addition, because we specify the rect directly in parent coords
	//be it in parents view or frame, we dont specify it in childrens rect coords
	Rect r = ctrl->GetRect();
	r.Offset(GetOffset(*ctrl, *pctrl) - r.TopLeft());

	rc.SetData(r);
}

void CtrlMover::State(int reason)
{
	if(reason != ENABLE) return;
	if(!IsEnabled()) rc.Remove();
}

CtrlMover::CtrlMover()
{
	WhenLeftDown = THISBACK(OnCtrlLeft);
	rcst = RectCtrl::StyleDefault();
	rcst.rectcol = Null;
	rc.SetStyle(rcst);
	rc <<= THISBACK(OnRectChange);
	rc.WhenMissed = THISBACK(OnMissed);
}
