#include "vectorwidget.h"
#include "gui_defines.h"

VectorWidget::VectorWidget()
	:ScrollBox(),
	selectedStroke(-1),
	selectedPoint(-1),
	selectedGradient(-1),
	editMode(0),
	drawMode(VGFX_STROKES | VGFX_GRADIENTS),
	client_w(0),
	client_h(0),
	offset_x(0),
	offset_y(0),
	zoom(1.0f)
{
}


void VectorWidget::SelectStroke(int i) {
	if (i < image->GetStrokeCount()) {
		selectedStroke = i;
		selectedPoint = -1;
		Redraw();
	}
}


void VectorWidget::SelectGradient(int i) {
	if (i < image->GetGradientCount()) {
		selectedGradient = i;
		Redraw();
	}
}


void VectorWidget::EditMode(int m) {
	editMode = m;
	Redraw();
}


void VectorWidget::EnableMode(int m) {
	drawMode |= m;
	Redraw();
}


void VectorWidget::DisableMode(int m) {
	drawMode &= ~m;
	Redraw();
}


void VectorWidget::DrawClientArea(Bitmap &canvas, int x, int y) {
	client_w = canvas.w();
	client_h = canvas.h();
	offset_x = x;
	offset_y = y;

	if (selectedStroke >= image->GetStrokeCount()) {
		selectedStroke = -1;
	}

	if (selectedGradient >= image->GetGradientCount()) {
		selectedGradient = -1;
	}

	image->Render(canvas, zoom, offset_x, offset_y, drawMode, editMode == 0 ? selectedStroke : -1, editMode == 1 ? selectedGradient : -1);
}


bool VectorWidget::MsgWantfocus() {
	ScrollBox::MsgWantfocus();
	return true;
}


bool VectorWidget::MsgWantmouse() {
	ScrollBox::MsgWantmouse();
	return true;
}


bool VectorWidget::MsgChar(int c) {
	if (ScrollBox::MsgChar(c)) return true;

	float dx = 0.0f;
	float dy = 0.0f;
	float old_zoom = zoom;

	switch (c>>8) {
		case KEY_PLUS_PAD:
			zoom *= 1.5f;
			if (zoom > 16.0f) zoom = 16.0f;
		break;

		case KEY_MINUS_PAD:
			zoom /= 1.5f;
			if (zoom < 1.0f) zoom = 1.0f;
		break;

		case KEY_LEFT:		dx = -0.01f;	break;
		case KEY_RIGHT:		dx = 0.01f;		break;
		case KEY_UP:		dy = -0.01f;	break;
		case KEY_DOWN:		dy = 0.01f;		break;

		default: return false;
	};

	if ((dx != 0.0f || dy != 0.0f) && selectedStroke != -1) {
		image->GetStroke(selectedStroke).Move(Vector2D(dx,dy));
		Redraw();
	}

	if (zoom != old_zoom) {
		SetScrollSize((int)(client_w * zoom), (int)(client_h * zoom));
	}

	return true;
}


void VectorWidget::MsgWheel(int z) {
	ScrollBox::MsgWheel(z);

	Point mp = GetMousePos();
	int mpx = (int)((offset_x + mp.x())/zoom);
	int mpy = (int)((offset_y + mp.y())/zoom);

	for (int i=0; i<z; i++) {
		zoom *= 1.05f;
	}
	for (int i=0; i>z; i--) {
		zoom /= 1.05f;
	}

	if (zoom < 1.0f)  zoom = 1.0f; else
	if (zoom > 16.0f) zoom = 16.0f;

	SetScrollSize((int)(client_w * zoom), (int)(client_h * zoom));
	mpx = (int)(mpx*zoom - mp.x());
	mpy = (int)(mpy*zoom - mp.y());
	ScrollTo(mpx, mpy);
}


void VectorWidget::MsgLPress() {
	ScrollBox::MsgLPress();

	if (editMode == 0) {
		if (selectedStroke >= 0 && selectedStroke < image->GetStrokeCount()) {
			Vector2D p = GetMousePosEx();
			selectedPoint = image->GetStroke(selectedStroke).Find(p, 4.0f / (float)client_w);
			if (selectedPoint == -1) {
				image->GetStroke(selectedStroke).Add(p);
				selectedPoint = image->GetStroke(selectedStroke).GetLength()-1;
				Redraw();
				GetParent()->HandleEvent(*this, MSG_UPDATE_GUI);
			}

			SetFlag(D_PRESSED);
		}
	}
	else {
		if (selectedGradient >= 0 && selectedGradient < image->GetGradientCount()) {
			Vector2D p = GetMousePosEx();
			selectedPoint = image->GetGradient(selectedGradient).Find(p, 4.0f / (float)client_w);
			if (selectedPoint == -1) {
				image->GetGradient(selectedGradient).AddPoint(p);
				selectedPoint = image->GetGradient(selectedGradient).GetPointCount()-1;
				Redraw();
				GetParent()->HandleEvent(*this, MSG_UPDATE_GUI);
			}

			SetFlag(D_PRESSED);
		}
	}
}

void VectorWidget::MsgLRelease() {
	ScrollBox::MsgLRelease();
	ClearFlag(D_PRESSED);
}

void VectorWidget::MsgMousemove(const Point &d) {
	ScrollBox::MsgMousemove(d);

	if (TestFlag(D_PRESSED)) {
		Vector2D p = GetMousePosEx();

		if (editMode == 0) {
			if (selectedStroke >= 0 && selectedStroke < image->GetStrokeCount()) {
				image->GetStroke(selectedStroke).SetPoint(selectedPoint, p);
			}
		}
		else {
			if (selectedGradient >= 0 && selectedGradient < image->GetGradientCount()) {
				switch (selectedPoint) {
					case -3:
					case -2:
						image->GetGradient(selectedGradient).SetAnchor(-2-selectedPoint, p);
					break;

					case -1:
					break;

					default:
						image->GetGradient(selectedGradient).SetPoint(selectedPoint, p);
					break;
				};
			}
		}

		Redraw();
	}
}

void VectorWidget::MsgRPress() {
	ScrollBox::MsgRPress();

	if (editMode == 0) {
		if (selectedStroke >= 0 && selectedStroke < image->GetStrokeCount()) {
			Vector2D p = GetMousePosEx();
			image->GetStroke(selectedStroke).Remove(p);

			Redraw();
			GetParent()->HandleEvent(*this, MSG_UPDATE_GUI);
		}
	}
	else {
		if (selectedGradient >= 0 && selectedGradient < image->GetGradientCount()) {
			Vector2D p = GetMousePosEx();
			image->GetGradient(selectedGradient).RemovePoint(p);
			Redraw();
			GetParent()->HandleEvent(*this, MSG_UPDATE_GUI);
		}
	}
}

Vector2D VectorWidget::GetMousePosEx() {
	Point mp = GetMousePos();
	Bitmap bmp = panel.GetBitmap();
	mp -= Point((bmp.w() - bmp.ThickX())/2, (bmp.h() - bmp.ThickY())/2);
	Vector2D p = Vector2D((float)(mp.x() + offset_x) / (float)(client_w*zoom), (float)(mp.y() + offset_y) / (float)(client_h*zoom));
	return p;
}
