#include "maindlg.h"


MainDialog::MainDialog() : Dialog() {
	desktop.Resize(SCREEN_W, SCREEN_H);
	Add(desktop);

	imgWidget.image = &image;
	int x = 200;
	int y = 4;
	int w = SCREEN_W - x - 8;
	int h = w*3/4;

	lblEditMode.Setup(x+8, y, 100, 16, 0, 0, "Edit mode", 0);
	Add(lblEditMode);

	rbEditStrokes.Setup(x+108, y, 80, 16, 0, 0, "strokes", 1);
	rbEditStrokes.Select();
	rbEditStrokes.SetCallbackID(MSG_EDIT_MODE_STROKES);
	Add(rbEditStrokes);

	rbEditGradients.Setup(x+108+80, y, 100, 16, 0, 0, "gradients", 1);
	rbEditGradients.SetCallbackID(MSG_EDIT_MODE_GRADIENTS);
	Add(rbEditGradients);

	y+=16;

	lblDrawMode.Setup(x+8, y, 100, 16, 0, 0, "Draw mode", 0);
	Add(lblDrawMode);

	chkDrawMode[0].Setup(x+108, y, 80, 16, 0, 0, "strokes");
	chkDrawMode[0].Select();
	chkDrawMode[0].SetCallbackID(MSG_DRAW_MODE_STROKES);
	Add(chkDrawMode[0]);

	chkDrawMode[1].Setup(x+188, y, 100, 16, 0, 0, "gradients");
	chkDrawMode[1].Select();
	chkDrawMode[1].SetCallbackID(MSG_DRAW_MODE_GRADIENTS);
	Add(chkDrawMode[1]);

	chkDrawMode[2].Setup(x+288, y, 100, 16, 0, 0, "background");
	chkDrawMode[2].SetCallbackID(MSG_DRAW_MODE_BACKGROUND);
	Add(chkDrawMode[2]);

	y+=16;

	imgWidget.Shape(x, y, w, h);
	Add(imgWidget);

	y += h+8;

	btnNew.Setup(x, y, 100, 20, 0, 0, "Clear");
	btnNew.SetCallbackID(MSG_NEW);
	Add(btnNew);

	btnLoad.Setup(x+108, y, 100, 20, 0, 0, "Load");
	btnLoad.SetCallbackID(MSG_LOAD);
	Add(btnLoad);

	btnSave.Setup(x+2*108, y, 100, 20, 0, 0, "Save");
	btnSave.SetCallbackID(MSG_SAVE);
	Add(btnSave);

	btnExport.Setup(x+3*108, y, 100, 20, 0, 0, "Export");
	btnExport.SetCallbackID(MSG_EXPORT);
	Add(btnExport);

	w = x - 12;
	x = 4;
	y = 4;

	lblStrokes.Shape(x, y, w, 16);
	lblStrokes.SetText("Strokes");
	Add(lblStrokes);

	lstStrokes.Shape(x, y+=16, w, 100);
	Add(lstStrokes);

	btnAddStroke.Setup(x, y+=104, w, 18, 0, 0, "Add");
	btnAddStroke.SetCallbackID(MSG_ADD_STROKE);
	Add(btnAddStroke);

	btnRemoveStroke.Setup(x, y+=20, w, 18, 0, 0, "Remove");
	btnRemoveStroke.SetCallbackID(MSG_REMOVE_STROKE);
	Add(btnRemoveStroke);

	btnColourStroke.Setup(x, y+=20, w, 18, 0, 0, "Colour");
	btnColourStroke.SetCallbackID(MSG_COLOUR_STROKE);
	Add(btnColourStroke);

	chkStrokeClose.Setup(x, (y+=20)+4, w, 16, 0, 0, "Close path");
	chkStrokeClose.SetCallbackID(MSG_STROKE_CLOSE);
	Add(chkStrokeClose);

	lblStrokeCaps.Setup(x, y+24, 2*w/5, 16, 0, 0, "round caps");
	Add(lblStrokeCaps);

	lstStrokeCaps.list.InsertItem(new ListItemString("both sides"), 0);
	lstStrokeCaps.list.InsertItem(new ListItemString("first point"), 1);
	lstStrokeCaps.list.InsertItem(new ListItemString("last point"), 2);
	lstStrokeCaps.list.InsertItem(new ListItemString("none"), 3);
	lstStrokeCaps.list.Select(0);
	lstStrokeCaps.list.h(96);
	lstStrokeCaps.Shape(x + 2*w/5, y+=20, 3*w/5, 20);
	lstStrokeCaps.SetCallbackID(MSG_STROKE_CAPS);
	Add(lstStrokeCaps);

	lblStrokeThickness.Setup(x, y+28, 2*w/5, 16, 0, 0, "thickness", 0);
	Add(lblStrokeThickness);

	sldStrokeThickness.Setup(x+2*w/5, y+=24, 3*w/5, 18, 0, 0, 0, 100, 10, 1);
	Add(sldStrokeThickness);

	lblStrokeCurviness.Setup(x, y+28, 2*w/5, 16, 0, 0, "curviness", 0);
	Add(lblStrokeCurviness);

	sldStrokeCurviness.Setup(x+2*w/5, y+=24, 3*w/5, 18, 0, 0, 0, 100, 10, 1);
	Add(sldStrokeCurviness);

	lblGradients.Shape(x, y+=28, w, 16);
	lblGradients.SetText("Gradients/fills");
	Add(lblGradients);

	lstGradients.Shape(x, y+=16, w, 110);
	Add(lstGradients);

	btnAddGradient.Setup(x, y+=114, w, 18, 0, 0, "Add");
	btnAddGradient.SetCallbackID(MSG_ADD_GRADIENT);
	Add(btnAddGradient);

	btnRemoveGradient.Setup(x, y+=20, w, 18, 0, 0, "Remove");
	btnRemoveGradient.SetCallbackID(MSG_REMOVE_GRADIENT);
	Add(btnRemoveGradient);

	btnColour1Gradient.Setup(x, y+=20, w, 18, 0, 0, "Colour 1");
	btnColour1Gradient.SetCallbackID(MSG_COLOUR_GRADIENT1);
	Add(btnColour1Gradient);

	btnColour2Gradient.Setup(x, y+=20, w, 18, 0, 0, "Colour 2");
	btnColour2Gradient.SetCallbackID(MSG_COLOUR_GRADIENT2);
	Add(btnColour2Gradient);

	rbGradientType[0].Setup(x+24, y+=24, w-24, 16, 0, 0, "Solid", 0);
	rbGradientType[0].Select();
	rbGradientType[0].SetCallbackID(MSG_GRADIENT_TYPE0);
	Add(rbGradientType[0]);

	rbGradientType[1].Setup(x+24, y+=16, w-24, 16, 0, 0, "Linear", 0);
	rbGradientType[1].SetCallbackID(MSG_GRADIENT_TYPE1);
	Add(rbGradientType[1]);

	rbGradientType[2].Setup(x+24, y+=16, w-24, 18, 0, 0, "Circle", 0);
	rbGradientType[2].SetCallbackID(MSG_GRADIENT_TYPE2);
	Add(rbGradientType[2]);

	lblBackground.Setup(x, (y+=20)+8, 120, 16, 0, 0, "Background", 0);
	Add(lblBackground);

	x+=100;

	for (int i=0; i<4; i++) {
		char tmp[32];
		usprintf(tmp, "%d", i+1);
		btnBackground[i].Setup(x + (i%2)*36, y + (i>=2 ? 24 : 0), 36, 24, 0, 0, tmp);
		btnBackground[i].SetCallbackID(MSG_COLOUR_BACKGROUND1+i);
		Add(btnBackground[i]);
	}


	btnExit.Setup(SCREEN_W - 128, SCREEN_H - 28, 120, 20, 0, D_EXIT, "Exit");
	Add(btnExit);

	MakeFullPath(path, "");
	escapeExits = false;
}


void MainDialog::HandleEvent(Widget &obj, int msg, int arg1, int arg2) {
	Dialog::HandleEvent(obj, msg, arg1, arg2);

	switch (msg) {
		case MSG_SCROLL:
			if (obj == lstStrokes)			OnSelectStroke(arg1);		else
			if (obj == lstGradients)		OnSelectGradient(arg1);		else
			if (obj == sldStrokeThickness)	OnStrokeThickness(arg1);	else
			if (obj == sldStrokeCurviness)	OnStrokeCurviness(arg1);
		break;

		case MSG_EDIT_MODE_STROKES:		OnEditMode(0);			break;
		case MSG_EDIT_MODE_GRADIENTS:	OnEditMode(1);			break;
		case MSG_DRAW_MODE_STROKES:		OnDrawMode(0);			break;
		case MSG_DRAW_MODE_GRADIENTS:	OnDrawMode(1);			break;
		case MSG_DRAW_MODE_BACKGROUND:	OnDrawMode(2);			break;
		case MSG_ADD_STROKE:			OnAddStroke();			break;
		case MSG_REMOVE_STROKE:			OnRemoveStroke();		break;
		case MSG_COLOUR_STROKE:			OnColourStroke();		break;
		case MSG_ADD_GRADIENT:			OnAddGradient();		break;
		case MSG_REMOVE_GRADIENT:		OnRemoveGradient();		break;
		case MSG_COLOUR_GRADIENT1:		OnColourGradient(0);	break;
		case MSG_COLOUR_GRADIENT2:		OnColourGradient(1);	break;
		case MSG_GRADIENT_TYPE0:		OnGradientType(0);		break;
		case MSG_GRADIENT_TYPE1:		OnGradientType(1);		break;
		case MSG_GRADIENT_TYPE2:		OnGradientType(2);		break;
		case MSG_COLOUR_BACKGROUND1:	OnColourBackground(0);	break;
		case MSG_COLOUR_BACKGROUND2:	OnColourBackground(1);	break;
		case MSG_COLOUR_BACKGROUND3:	OnColourBackground(2);	break;
		case MSG_COLOUR_BACKGROUND4:	OnColourBackground(3);	break;
		case MSG_NEW:					OnNew();				break;
		case MSG_SAVE:					OnSave();				break;
		case MSG_LOAD:					OnLoad();				break;
		case MSG_EXPORT:				OnExport();				break;
		case MSG_UPDATE_GUI:			OnUpdateGUI();			break;
		case MSG_STROKE_CLOSE:			OnStrokeClose();		break;
		case MSG_STROKE_CAPS:			OnStrokeCaps(arg1);		break;
	};
}


void MainDialog::OnEditMode(int mode) {
	imgWidget.EditMode(mode);
}


void MainDialog::OnDrawMode(int i) {
	int mode = 0;
	switch (i) {
		case 0:		mode = VGFX_STROKES;		break;
		case 1:		mode = VGFX_GRADIENTS;		break;
		case 2:		mode = VGFX_BACKGROUND;		break;
	};

	if (chkDrawMode[i].Selected()) {
		imgWidget.EnableMode(mode);
	}
	else {
		imgWidget.DisableMode(mode);
	}
}


void MainDialog::OnAddStroke() {
	image.AddStroke();
	OnUpdateGUI();
	OnSelectStroke(lstStrokes.GetSelectedIndex());
}


void MainDialog::OnRemoveStroke() {
	int sel = lstStrokes.GetSelectedIndex();
	if (sel >= 0) {
		image.RemoveStroke(sel);
		OnUpdateGUI();
		imgWidget.Redraw();
		OnSelectStroke(lstStrokes.GetSelectedIndex());
	}
}


void MainDialog::OnColourStroke() {
	int sel = lstStrokes.GetSelectedIndex();
	if (sel >= 0) {
		int old = image.GetStroke(sel).GetColour();
		ColorSelect dlg("Select colour", old);
		int col = dlg.Popup(this);
		if (col != -1) {
			image.GetStroke(sel).SetColour(col);
			imgWidget.Redraw();
		}
	}
}


void MainDialog::OnAddGradient() {
	image.AddGradient();
	OnUpdateGUI();
	OnSelectGradient(lstGradients.GetSelectedIndex());
}


void MainDialog::OnRemoveGradient() {
	int sel = lstGradients.GetSelectedIndex();
	if (sel >= 0) {
		image.RemoveGradient(sel);
		OnUpdateGUI();
		imgWidget.Redraw();
		OnSelectGradient(lstGradients.GetSelectedIndex());
	}
}


void MainDialog::OnColourGradient(int i) {
	int sel = lstGradients.GetSelectedIndex();
	if (sel >= 0) {
		int old = image.GetGradient(sel).GetColour(i);
		ColorSelect dlg("Select colour", old);
		int col = dlg.Popup(this);
		if (col != -1) {
			image.GetGradient(sel).SetColour(i, col);
			imgWidget.Redraw();
		}
	}
}


void MainDialog::OnGradientType(int type) {
	int sel = lstGradients.GetSelectedIndex();
	if (sel >= 0) {
		image.GetGradient(sel).SetType(type);
		imgWidget.Redraw();
	}
}


void MainDialog::OnColourBackground(int i) {
	int old = image.GetBackground(i);
	ColorSelect dlg("Select colour", old);
	int col = dlg.Popup(this);
	if (col != -1) {
		image.SetBackground(i, col);
		imgWidget.Redraw();
	}
}


void MainDialog::OnNew() {
	image.Clear();
	imgWidget.Redraw();
	OnUpdateGUI();
}


void MainDialog::OnSave() {
	FileSelect dlg("Save file", path, "Vector GFX (*.vgfx)|All files (*.*)");
	char *selPath = dlg.Popup(this);
	if (selPath) {
		ustrcpy(path, selPath);
		char *ext = get_extension(selPath);
		if (ustrlen(ext) == 0) {
			ustrcat(path, ".vgfx");
		}
		image.Save(path);
		imgWidget.Redraw();
	}
}


void MainDialog::OnLoad() {
	FileSelect dlg("Load file", path, "Vector GFX (*.vgfx)|All files (*.*)");
	char *selPath = dlg.Popup(this);
	if (selPath) {
		ustrcpy(path, selPath);
		image.Load(path);
		imgWidget.Redraw();
		OnUpdateGUI();

		if (image.GetStrokeCount() > 0) {
			OnSelectStroke(0);
		}
		else {
			OnSelectStroke(-1);
		}

		if (image.GetGradientCount() > 0) {
			OnSelectGradient(0);
		}
		else {
			OnSelectGradient(-1);
		}
	}
}


void MainDialog::OnExport() {
	Window wnd;
	Label lblSize;
	ComboBox lstSize;
	Button btnOK;

	wnd.GetClientArea()->Resize(200, 68);

	lblSize.Setup(8, 8, 60, 16, 0, 0, "size", 0);
	wnd.Add(lblSize);

	int w[] = { 640, 800, 1024, 1280, 1600 };
	int h[] = { 480, 600,  768,  960, 1200 };
	for (int i=0; i<5; i++) {
		char tmp[32];
		usprintf(tmp, "%dx%d", w[i], h[i]);
		lstSize.list.InsertItem(new ListItemString(tmp), i);
	}
	lstSize.list.Select(0);
	lstSize.Shape(72, 8, 120, 24);
	wnd.Add(lstSize);

	btnOK.Setup(16, 40, 168, 24, 0, D_EXIT, "OK");
	wnd.Add(btnOK);

	wnd.title.SetText("Bitmap size");
	wnd.Resize(200,68);
	wnd.Centre();
	wnd.Popup(this);

	FileSelect dlg("Export file", path, "TGA images (*.tga)|All files (*.*)");
	char *selPath = dlg.Popup(this);
	if (selPath) {
		ustrcpy(path, selPath);
		char *ext = get_extension(selPath);
		if (ustrlen(ext) == 0) {
			ustrcat(path, ".tga");
		}

		BITMAP *bmp = create_bitmap(w[lstSize.list.Selection()], h[lstSize.list.Selection()]);
		image.Render(bmp);
		save_bitmap(path, bmp, 0);
		destroy_bitmap(bmp);
	}
}


void MainDialog::OnUpdateGUI() {
	int sel = lstStrokes.GetSelectedIndex();
	lstStrokes.DeleteAllItems();
	for (int i=0; i<image.GetStrokeCount(); i++) {
		char tmp[128];
		usprintf(tmp, "%d (%d points)", i, image.GetStroke(i).GetLength());
		lstStrokes.InsertItem(tmp);
	}
	if (sel < 0 || sel >= image.GetStrokeCount()) {
		sel = 0;
	}
	lstStrokes.Select(sel);

	sel = lstGradients.GetSelectedIndex();
	lstGradients.DeleteAllItems();
	for (int i=0; i<image.GetGradientCount(); i++) {
		char tmp[128];
		usprintf(tmp, "%d (%d points)", i, image.GetGradient(i).GetPointCount());
		lstGradients.InsertItem(tmp);
	}
	if (sel < 0 || sel >= image.GetGradientCount()) {
		sel = 0;
	}
	lstGradients.Select(sel);
}


void MainDialog::OnSelectStroke(int i) {
	if (i >= image.GetStrokeCount()) return;

	imgWidget.SelectStroke(i);

	if (i >= 0) {
		if (image.GetStroke(i).TestFlag(VGFX_CLOSE_PATH)) {
			chkStrokeClose.Select();
		}
		else {
			chkStrokeClose.Deselect();
		}

		if (image.GetStroke(i).TestFlag(VGFX_CAPS_BOTH)) {
			lstStrokeCaps.list.Select(0);
		}
		else if (image.GetStroke(i).TestFlag(VGFX_CAPS_FIRST)) {
			lstStrokeCaps.list.Select(1);
		}
		else if (image.GetStroke(i).TestFlag(VGFX_CAPS_LAST)) {
			lstStrokeCaps.list.Select(2);
		}
		else {
			lstStrokeCaps.list.Select(3);
		}
		lstStrokeCaps.editBox.SetText(lstStrokeCaps.list.GetSelectedItem()->GetText());

		sldStrokeThickness.SetPosition((int)(image.GetStroke(i).GetThickness()*5000));
		sldStrokeCurviness.SetPosition((int)(image.GetStroke(i).GetCurviness()*100));
	}
}


void MainDialog::OnSelectGradient(int which) {
	if (which >= image.GetGradientCount()) return;

	imgWidget.SelectGradient(which);

	if (which >= 0) {
		for (int i=0; i<3; i++) {
			rbGradientType[i].Deselect();
		}

		rbGradientType[image.GetGradient(which).GetType()].Select();
	}
}


void MainDialog::OnStrokeClose() {
	int sel = lstStrokes.GetSelectedIndex();
	if (sel >= 0) {
		image.GetStroke(sel).SetFlag(VGFX_CLOSE_PATH, chkStrokeClose.Selected());
		imgWidget.Redraw();
	}
}


void MainDialog::OnStrokeThickness(int val) {
	int sel = lstStrokes.GetSelectedIndex();
	if (sel >= 0) {
		image.GetStroke(sel).SetThickness((float)val / 5000.0f);
		imgWidget.Redraw();
	}
}


void MainDialog::OnStrokeCurviness(int val) {
	int sel = lstStrokes.GetSelectedIndex();
	if (sel >= 0) {
		image.GetStroke(sel).SetCurviness((float)val / 100.0f);
		imgWidget.Redraw();
	}
}


void MainDialog::OnStrokeCaps(int i) {
	int sel = lstStrokes.GetSelectedIndex();
	if (sel >= 0) {
		switch (i) {
			case 0:
				image.GetStroke(sel).SetFlag(VGFX_CAPS_BOTH);
			break;

			case 1:
				image.GetStroke(sel).SetFlag(VGFX_CAPS_FIRST, true);
				image.GetStroke(sel).SetFlag(VGFX_CAPS_LAST, false);
			break;

			case 2:
				image.GetStroke(sel).SetFlag(VGFX_CAPS_FIRST, false);
				image.GetStroke(sel).SetFlag(VGFX_CAPS_LAST, true);
			break;

			case 3:
				image.GetStroke(sel).SetFlag(VGFX_CAPS_FIRST, false);
				image.GetStroke(sel).SetFlag(VGFX_CAPS_LAST, false);
			break;
		};

		imgWidget.Redraw();
	}
}
