/*
**	FILE:			LgiRes_Dialog.h
**	AUTHOR:			Matthew Allen
**	DATE:			5/8/1999
**	DESCRIPTION:	Dialog Resource Editor
**
**
**	Copyright (C) 1999, Matthew Allen
**		fret@memecode.com
*/

#ifndef __LGIRES_DIALOG_H
#define __LGIRES_DIALOG_H

#include "lgi/common/Res.h"
#include "LgiRes_String.h"

class ResDialog;
class ResDialogUi;

#define UI_CURSOR				0
#define UI_TABLE				1
#define UI_TEXT					2
#define UI_EDITBOX				3
#define UI_CHECKBOX				4
#define UI_BUTTON				5
#define UI_GROUP				6
#define UI_RADIO				7
#define UI_TABS					8
#define	UI_LIST					9
#define UI_COMBO				10
#define UI_TREE					11
#define UI_BITMAP				12
#define UI_PROGRESS				13
#define UI_SCROLL_BAR			14
#define UI_CUSTOM				15
#define UI_TAB					16
#define UI_COLUMN				17
#define UI_CONTROL_TREE			18
#define UI_DIALOG				100

#define GOOBER_SIZE				5
#define GOOBER_BORDER			7

#define GRID_X					7
#define GRID_Y					7

////////////////////////////////////////////////////////////////
#define DECL_DIALOG_CTRL(id)	 \
	int GetType() { return id; } \
	LView *View() { return this; } \
	void OnMouseClick(LMouse &m); \
	void OnMouseMove(LMouse &m); \
	void OnPaint(LSurface *pDC);

#define IMPL_DIALOG_CTRL(cls)	 \
	void cls::OnMouseClick(LMouse &m) { ResDialogCtrl::OnMouseClick(m); } \
	void cls::OnMouseMove(LMouse &m) { ResDialogCtrl::OnMouseMove(m); }

enum DlgSelectMode
{
	SelNone,
	SelSet,
	SelAdd,
};

class ResDialogCtrl : public FieldSource, public ResObject
{
	friend class ResDialog;

	ResString *_Str;

protected:
	static int TabDepth;

	void TabString(char *Str);
	void ReadPos(char *Str);
	char *GetRefText();

	LRect Goobers[8];
	int OverGoober;

	ResDialog *Dlg;
	LRect Title;
	LRect Client;
	int DragCtrl;
	LRect DragRgn;
	LPoint DragStart;
	bool MoveCtrl;
	DlgSelectMode SelectMode;
	LRect SelectStart;

	bool AcceptChildren;
	bool Movable;
	bool Vis;
	LAutoString CssClass;
	LAutoString CssStyle;

	LMouse MapToDialog(LMouse m);

public:
	ResDialogCtrl(ResDialog *dlg, char *CtrlTypeName, LXmlTag *load);
	~ResDialogCtrl();

	const char *GetClass() { return "ResDialogCtrl"; }
	virtual LView *View() = 0;
	ResDialogCtrl *ParentCtrl() { return dynamic_cast<ResDialogCtrl*>(View()->GetParent()); }
	ResDialog *GetDlg() { return Dlg; }
	ResString *GetStr() { return _Str; }
	bool SetStr(ResString *s);

	bool IsContainer() { return AcceptChildren; }
	void OnPaint(LSurface *pDC);
	void OnMouseClick(LMouse &m);
	void OnMouseMove(LMouse &m);
	bool SetPos(LRect &p, bool Repaint = false);
	void StrFromRef(int Id);
	LRect AbsPos();
	bool GetFields(FieldTree &Fields);

	// Copy/Paste translations only
	void CopyText();
	void PasteText();

	virtual int GetType() = 0;
	virtual LRect GetMinSize();
	virtual bool Serialize(FieldTree &Fields);
	virtual void ListChildren(List<ResDialogCtrl> &l, bool Deep = true);
	virtual bool AttachCtrl(ResDialogCtrl *Ctrl, LRect *r = 0);
	virtual LRect *GetChildArea(ResDialogCtrl *Ctrl) { return 0; }
	virtual LRect *GetPasteArea() { return 0; }
	virtual void EnumCtrls(List<ResDialogCtrl> &Ctrls);
	virtual void ShowMe(ResDialogCtrl *Child) {}
};

#define RESIZE_X1			0x0001
#define RESIZE_Y1			0x0002
#define RESIZE_X2			0x0004
#define RESIZE_Y2			0x0008

class ResDialog : public Resource, public LLayout, public ResFactory
{
	friend class ResDialogCtrl;
	friend class ResDialogUi;
	friend class CtrlDlg;
	friend class CtrlTabs;
	friend class CtNode;

protected:
	static int SymbolRefs;
	static ResStringGroup *Symbols;
	static bool CreateSymbols;

	ResDialogUi *Ui;
	List<ResDialogCtrl> Selection;
	LRect DlgPos;
	
	int DragGoober;
	int *DragX, *DragY;
	int DragOx, DragOy;
	LRect DragRgn;
	ResDialogCtrl *DragCtrl;
	void DrawSelection(LSurface *pDC);

public:
	LAutoPtr<LSurface> DebugOverlay;

	ResDialog(AppWnd *w, int type = TYPE_DIALOG);
	~ResDialog();
	void Create(LXmlTag *load, SerialiseContext *Ctx) override;

	const char *GetClass() override { return "ResDialog"; }
	LView *Wnd() override { return dynamic_cast<LView*>(this); }
	static void AddLanguage(LLanguageId Id);
	ResDialog *IsDialog() override { return this; }
	void EnumCtrls(List<ResDialogCtrl> &Ctrls);
	void OnChildrenChanged(LViewI *Wnd, bool Attaching) override;

	// GObj overrides
	const char *Name() override;
	bool Name(const char *n) override;

	// Factory
	char *StringFromRef(int Ref) override;
	ResObject *CreateObject(LXmlTag *Tag, ResObject *Parent) override;

	int Res_GetStrRef(ResObject *Obj) override;
	bool Res_SetStrRef(ResObject *Obj, int Id, ResReadCtx *Ctx) override;
	void Res_SetPos(ResObject *Obj, int x1, int y1, int x2, int y2) override;
	void Res_SetPos(ResObject *Obj, char *s) override;
	LRect Res_GetPos(ResObject *Obj) override;
	void Res_Attach(ResObject *Obj, ResObject *Parent) override;
	bool Res_GetChildren(ResObject *Obj, List<ResObject> *l, bool Deep) override;
	void Res_Append(ResObject *Obj, ResObject *Parent) override;
	bool Res_GetItems(ResObject *Obj, List<ResObject> *l) override;
	bool Res_GetProperties(ResObject *Obj, LDom *Props) override;
	bool Res_SetProperties(ResObject *Obj, LDom *Props) override;
	LDom *Res_GetDom(ResObject *Obj) override;

	// Implementation
	int CurrentTool();
	ResDialogCtrl *CreateCtrl(LXmlTag *Tag);
	ResDialogCtrl *CreateCtrl(int Tool, LXmlTag *load);
	bool IsSelected(ResDialogCtrl *Ctrl);
	bool IsDraging();
	void SnapPoint(LPoint *p, ResDialogCtrl *From);
	void SnapRect(LRect *r, ResDialogCtrl *From);
	void MoveSelection(int Dx, int Dy);
	void SelectRect(ResDialogCtrl *Parent, LRect *r, bool ClearPrev = true);
	void SelectNone();
	void SelectCtrl(ResDialogCtrl *c);
	void CleanSymbols();
	ResString *CreateSymbol();
	void OnShowLanguages() override;

	// Copy/Paste whole controls
	void Delete() override;
	void Copy(bool Delete = false) override;
	void Paste() override;

	// Methods
	LView *CreateUI() override;
	void OnMouseClick(LMouse &m) override;
	void OnMouseMove(LMouse &m) override;
	bool OnKey(LKey &k) override;
	void OnSelect(ResDialogCtrl *Wnd, bool ClearPrev = true);
	void OnDeselect(ResDialogCtrl *Wnd);
	void OnRightClick(LSubMenu *RClick) override;
	void OnCommand(int Cmd) override;
	int OnCommand(int Cmd, int Event, OsView hWnd) override;
	void OnLanguageChange();

	void _Paint(LSurface *pDC = NULL, LPoint *Offset = NULL, LRect *Update = NULL) override;
	void OnPaint(LSurface *pDC) override;

	bool Test(ErrorCollection *e) override;
	bool Read(LXmlTag *Tag, SerialiseContext &Ctx) override;
	bool Write(LXmlTag *Tag, SerialiseContext &Ctx) override;
};

class ResDialogUi : public LLayout
{
	friend class ResDialog;

	LToolBar *Tools;
	ResDialog *Dialog;
	LStatusBar *Status;
	LStatusPane *StatusInfo;

public:
	ResDialogUi(ResDialog *Res);
	~ResDialogUi();

	const char *GetClass() { return "ResDialogUi"; }
	void OnPaint(LSurface *pDC);
	void PourAll();
	void OnPosChange();
	void OnCreate();
	LMessage::Result OnEvent(LMessage *Msg);

	int CurrentTool();
	void SelectTool(int i);
};

///////////////////////////////////////////////////////////////////////
class CtrlDlg : public ResDialogCtrl, public LView
{
public:
	CtrlDlg(ResDialog *dlg, LXmlTag *load);

	DECL_DIALOG_CTRL(UI_DIALOG)
	const char *GetClass() { return "CtrlDlg"; }

	LRect &GetClient(bool InClientSpace = true);
	
	// void _Paint(LSurface *pDC = NULL, LPoint *Offset = NULL, LRect *Update = NULL);
	void OnNcPaint(LSurface *pDC, LRect &r);
};

class CtrlTable : public ResDialogCtrl, public LDom, public LView
{
	class CtrlTablePrivate *d;

public:
	CtrlTable(ResDialog *dlg, LXmlTag *load);
	~CtrlTable();

	DECL_DIALOG_CTRL(UI_TABLE)
	const char *GetClass() { return "CtrlTable"; }

	bool GetFields(FieldTree &Fields);
	bool Serialize(FieldTree &Fields);

	void SetAttachCell(class ResTableCell *c);
	bool AttachCtrl(ResDialogCtrl *Ctrl, LRect *r = 0);
	void OnChildrenChanged(LViewI *Wnd, bool Attaching);
	LRect *GetPasteArea();
	LRect *GetChildArea(ResDialogCtrl *Ctrl);
	void Layout();
	void UnMerge(class ResTableCell *Cell);
	void Fix();
	void InsertCol(int x);
	void InsertRow(int y);
	void EnumCtrls(List<ResDialogCtrl> &Ctrls);
	void OnPosChange();

	bool GetVariant(const char *Name, LVariant &Value, const char *Array = 0);
	bool SetVariant(const char *Name, LVariant &Value, const char *Array = 0);
};

class CtrlText : public ResDialogCtrl, public LView
{
public:
	CtrlText(ResDialog *dlg, LXmlTag *load);

	DECL_DIALOG_CTRL(UI_TEXT)
	const char *GetClass() { return "CtrlText"; }
};

class CtrlEditbox : public ResDialogCtrl, public LView
{
	bool Password;
	bool MultiLine;

public:
	CtrlEditbox(ResDialog *dlg, LXmlTag *load);

	DECL_DIALOG_CTRL(UI_EDITBOX)
	const char *GetClass() { return "CtrlEditbox"; }

	bool GetFields(FieldTree &Fields);
	bool Serialize(FieldTree &Fields);
};

class CtrlCheckbox : public ResDialogCtrl, public LView
{
public:
	CtrlCheckbox(ResDialog *dlg, LXmlTag *load);

	DECL_DIALOG_CTRL(UI_CHECKBOX)
	const char *GetClass() { return "CtrlCheckbox"; }
};

class CtrlButton : public ResDialogCtrl, public LView
{
	LString Image;
	bool IsToggle;

public:
	CtrlButton(ResDialog *dlg, LXmlTag *load);

	DECL_DIALOG_CTRL(UI_BUTTON)
	const char *GetClass() { return "CtrlButton"; }
	bool GetFields(FieldTree &Fields);
	bool Serialize(FieldTree &Fields);
};

class CtrlGroup : public ResDialogCtrl, public LView
{
public:
	CtrlGroup(ResDialog *dlg, LXmlTag *load);

	DECL_DIALOG_CTRL(UI_GROUP)
	const char *GetClass() { return "CtrlGroup"; }
};

class CtrlRadio : public ResDialogCtrl, public LView
{
	LSurface *Bmp;

public:
	CtrlRadio(ResDialog *dlg, LXmlTag *load);
	~CtrlRadio();

	DECL_DIALOG_CTRL(UI_RADIO)
	const char *GetClass() { return "CtrlRadio"; }
};

class CtrlTab : public ResDialogCtrl, public LView
{
public:
	CtrlTab(ResDialog *dlg, LXmlTag *load);

	DECL_DIALOG_CTRL(UI_TAB)
	const char *GetClass() { return "CtrlTab"; }

	void ListChildren(List<ResDialogCtrl> &l, bool Deep);
};

class CtrlTabs : public ResDialogCtrl, public LView
{
	friend class CtrlTab;

	ssize_t Current;

public:
	List<CtrlTab> Tabs;

	CtrlTabs(ResDialog *dlg, LXmlTag *load);
	~CtrlTabs();

	DECL_DIALOG_CTRL(UI_TABS)
	const char *GetClass() { return "CtrlTabs"; }

	void ListChildren(List<ResDialogCtrl> &l, bool Deep);
	void Empty();
	void ToTab();
	void FromTab();

	LRect GetMinSize();
	void EnumCtrls(List<ResDialogCtrl> &Ctrls);
	void ShowMe(ResDialogCtrl *Child);
};

class ListCol : public ResDialogCtrl, public LView
{
public:
	LRect &r() { return GetPos(); }

	DECL_DIALOG_CTRL(UI_COLUMN)
	const char *GetClass() { return "ListCol"; }

	ListCol(ResDialog *dlg, LXmlTag *load, char *Str = 0, int Width = 50);
};

class CtrlList : public ResDialogCtrl, public LView
{
	ssize_t DragCol;

public:
	List<ListCol> Cols;

	CtrlList(ResDialog *dlg, LXmlTag *load);
	~CtrlList();

	DECL_DIALOG_CTRL(UI_LIST)
	const char *GetClass() { return "CtrlList"; }

	void ListChildren(List<ResDialogCtrl> &l, bool Deep);
	void Empty();
};

class CtrlComboBox : public ResDialogCtrl, public LView
{
public:
	CtrlComboBox(ResDialog *dlg, LXmlTag *load);

	DECL_DIALOG_CTRL(UI_COMBO)
	const char *GetClass() { return "CtrlComboBox"; }
};

class CtrlScrollBar : public ResDialogCtrl, public LView
{
public:
	CtrlScrollBar(ResDialog *dlg, LXmlTag *load);

	DECL_DIALOG_CTRL(UI_SCROLL_BAR)
	const char *GetClass() { return "CtrlScrollBar"; }
};

class CtrlTree : public ResDialogCtrl, public LView
{
public:
	CtrlTree(ResDialog *dlg, LXmlTag *load);

	DECL_DIALOG_CTRL(UI_TREE)
	const char *GetClass() { return "CtrlTree"; }
};

class CtrlBitmap : public ResDialogCtrl, public LView
{
public:
	CtrlBitmap(ResDialog *dlg, LXmlTag *load);

	DECL_DIALOG_CTRL(UI_BITMAP)
	const char *GetClass() { return "CtrlBitmap"; }
};

class CtrlProgress : public ResDialogCtrl, public LView
{
public:
	CtrlProgress(ResDialog *dlg, LXmlTag *load);

	DECL_DIALOG_CTRL(UI_PROGRESS)
	const char *GetClass() { return "CtrlProgress"; }
};

class CtrlCustom : public ResDialogCtrl, public LView
{
	char *Control;

public:
	CtrlCustom(ResDialog *dlg, LXmlTag *load);
	~CtrlCustom();

	DECL_DIALOG_CTRL(UI_CUSTOM)
	const char *GetClass() { return "CtrlCustom"; }

	bool GetFields(FieldTree &Fields);
	bool Serialize(FieldTree &Fields);
};

class CtrlControlTree : public ResDialogCtrl, public LTree, public LDom
{
	class CtrlControlTreePriv *d;

public:
	CtrlControlTree(ResDialog *dlg, LXmlTag *load);
	~CtrlControlTree();

	DECL_DIALOG_CTRL(UI_CONTROL_TREE)
	const char *GetClass() { return "CtrlControlTree"; }

	bool GetFields(FieldTree &Fields);
	bool Serialize(FieldTree &Fields);

	bool GetVariant(const char *Name, LVariant &Value, const char *Array = 0);
	bool SetVariant(const char *Name, LVariant &Value, const char *Array = 0);
};

////////////////////////////////////////////////////////////////
#endif
