MODULE FormGen;
(**
	project	= "BlackBox"
	organization	= "www.oberon.ch"
	contributors	= "Oberon microsystems"
	version	= "System/Rsrc/About"
	copyright	= "System/Rsrc/About"
	license	= "Docu/BB-License"
	purpose	= ""
	changes	= "
	- YYYYMMDD, nn, ...
	"
	issues	= "
	- ...
	"

**)
	
	IMPORT
		Strings, Meta, Dates, Files, Ports, Views, Properties, Dialog, Containers, Documents,
		Controls, StdDialog, StdCmds, FormModels, FormViews, FormControllers;

	CONST
		defaultDelta = 4 * Ports.point;
		minW = 10 * Ports.mm; minH = 4 * Ports.mm;
		maxW = 200 * Ports.mm; maxH = 50 * Ports.mm;
		
	TYPE
		ProcVal = RECORD (Meta.Value)
			p: PROCEDURE
		END;

	VAR
		new*: RECORD
			link*: Dialog.String
		END;

		list: RECORD (Meta.Value) p*: POINTER TO Dialog.List END;
		select: RECORD (Meta.Value) p*: POINTER TO Dialog.Selection END;
		combo: RECORD (Meta.Value) p*: POINTER TO Dialog.Combo END;
		date: RECORD (Meta.Value) p*: POINTER TO Dates.Date END;
		time: RECORD (Meta.Value) p*: POINTER TO Dates.Time END;
		color: RECORD (Meta.Value) p*: POINTER TO Dialog.Color END;
		currency: RECORD (Meta.Value) p*: POINTER TO Dialog.Currency END;
		tree: RECORD (Meta.Value) p*: POINTER TO Dialog.Tree END;


	PROCEDURE GetSize (v: Views.View; VAR w, h: INTEGER);
	BEGIN
		w := Views.undefined; h := Views.undefined;
		Properties.PreferredSize(v, minW, maxW, minH, maxH, minW, minH, w, h)
	END GetSize;

	PROCEDURE Gen (f: FormModels.Model; fv: FormViews.View; VAR path, name: ARRAY OF CHAR;
					wr: FormModels.Writer; var: Meta.Item; VAR x, y, max: INTEGER; VAR first: BOOLEAN);
		VAR v, str: Views.View; dummy, delta, x0, y0, m, w, h, i: INTEGER; n: Meta.Name;
			p: Controls.Prop; s: Meta.Scanner; elem: Meta.Item; ok, back: BOOLEAN; pv: ProcVal;
	BEGIN
		dummy := 0; delta := defaultDelta; FormViews.RoundToGrid(fv, dummy, delta);
		NEW(p); p.guard := ""; p.notifier := ""; p.label := ""; p.level := 0;
		p.opt[0] := FALSE; p.opt[1] := FALSE; p.opt[2] := FALSE; p.opt[3] := FALSE; p.opt[4] := FALSE;
		back := FALSE;
		FormViews.RoundToGrid(fv, x, y);
		v := NIL; w := Views.undefined; x0 := x; y0 := y;
		IF (name[0] >= "0") & (name[0] <= "9") THEN p.link := path + "[" + name + "]"
		ELSIF name # "" THEN p.link := path + "." + name
		ELSE p.link := path$
		END;
		IF var.obj = Meta.modObj THEN	(* traverse module *)
			s.ConnectTo(var); s.Scan; m := 0;
			WHILE ~ s.eos DO
				s.GetObjName(n);
				Gen(f, fv, p.link, n, wr, s.this, x, y, m, first);
				s.Scan
			END;
			IF m > max THEN max := m END;
		ELSIF var.obj = Meta.procObj THEN
			var.GetVal(pv, ok);
			IF ok THEN	(* command *)
				IF first THEN p.opt[Controls.default] := TRUE END;
				p.label := name$; v := Controls.dir.NewPushButton(p);
				p.opt[Controls.default] := FALSE; first := FALSE
			END
		ELSIF var.obj = Meta.varObj THEN
			IF (var.typ IN {Meta.byteTyp, Meta.sIntTyp, Meta.longTyp, Meta.intTyp, Meta.sRealTyp, Meta.realTyp})
				OR (var.typ = Meta.arrTyp) & (var.BaseTyp() = Meta.charTyp) THEN
			p.opt[Controls.left] := TRUE; v := Controls.dir.NewField(p)
			ELSIF var.typ = Meta.boolTyp THEN
				p.label := name$; v := Controls.dir.NewCheckBox(p)
			ELSIF var.typ = Meta.procTyp THEN
				var.GetVal(pv, ok);
				IF ok THEN	(* command *)
					IF first THEN p.opt[Controls.default] := TRUE END;
					p.label := name$; v := Controls.dir.NewPushButton(p);
					p.opt[Controls.default] := FALSE; first := FALSE
				END
			ELSIF var.typ = Meta.recTyp THEN
				IF var.Is(list) THEN v := Controls.dir.NewListBox(p)
				ELSIF var.Is(select) THEN v := Controls.dir.NewSelectionBox(p)
				ELSIF var.Is(combo) THEN v := Controls.dir.NewComboBox(p)
				ELSIF var.Is(date) THEN v := Controls.dir.NewDateField(p)
				ELSIF var.Is(time) THEN v := Controls.dir.NewTimeField(p)
				ELSIF var.Is(color) THEN v := Controls.dir.NewColorField(p)
				ELSIF var.Is(currency) THEN p.opt[Controls.left] := TRUE; v := Controls.dir.NewField(p)
				ELSIF var.Is(tree) THEN 
					p.opt[Controls.haslines] := TRUE; p.opt[Controls.hasbuttons] := TRUE; 
					p.opt[Controls.atroot] := TRUE; p.opt[Controls.foldericons] := TRUE;
					v := Controls.dir.NewTreeControl(p)
				ELSE	(* traverse record *)
					s.ConnectTo(var); s.Scan; m := 0;
					IF name # "" THEN INC(x, delta); INC(y, 4 * delta) END;
					WHILE ~ s.eos DO
						s.GetObjName(n);
						Gen(f, fv, p.link, n, wr, s.this, x, y, m, first);
						s.Scan
					END;
					IF m > max THEN max := m END;
					IF (name # "") & (m > 0) THEN	(* insert group *)
						p.label := name$; v := Controls.dir.NewGroup(p);
						w := m; x := x0; h := y + delta - y0; y := y0; back := TRUE
					END
				END
			ELSIF var.typ = Meta.arrTyp THEN	(* traverse array *)
				i := 0; m := 0;
				IF name # "" THEN INC(x, delta); INC(y, 4 * delta) END;
				WHILE i < var.Len() DO
					var.Index(i, elem);
					Strings.IntToString(i, n); 
					Gen(f, fv, p.link, n, wr, elem, x, y, m, first);
					INC(i)
				END;
				IF m > max THEN max := m END;
				IF (name # "") & (m > 0) THEN	(* insert group *)
					p.label := name$; v := Controls.dir.NewGroup(p);
					w := m; x := x0; h := y + delta - y0; y := y0; back := TRUE
				END
			END
		END;
		IF v # NIL THEN
			IF (name # "") & (p.label = "") THEN
				p.label := name$;
				str := Controls.dir.NewCaption(p); GetSize(str, w, h);
				wr.WriteView(str, x, y, x + w, y + h); INC(x, w + delta);
				FormViews.RoundToGrid(fv, x, y)
			END;
			IF ~back THEN GetSize(v, w, h) END;
			wr.WriteView(v, x, y, x + w, y + h); INC(x, w + delta);
			IF back THEN f.PutAbove(v, NIL) END;
			y := y + h + delta
		END;
		IF x > max THEN max := x END;
		x := x0
	END Gen;

	PROCEDURE NewDialog (name: ARRAY OF CHAR): Views.View;
		VAR var: Meta.Item;  x, y, max: INTEGER; wr: FormModels.Writer; d: Documents.Document;
			f: FormModels.Model; v: FormViews.View; first: BOOLEAN; n: ARRAY 4 OF CHAR;
			c: Containers.Controller;
	BEGIN
		f := NIL; v := NIL;
		Meta.LookupPath(name, var);
		IF (var.obj = Meta.varObj) OR (var.obj = Meta.modObj) THEN
			x := defaultDelta; y := defaultDelta; max := 50 * Ports.point; first := TRUE;
			f := FormModels.dir.New();
			v := FormViews.dir.New(f); c := v.ThisController();
			IF c # NIL THEN
				c.SetOpts(Containers.layout) 
			ELSE
				v.SetController(FormControllers.dir.NewController(Containers.layout)) 
			END;
			wr := f.NewWriter(NIL); wr.Set(NIL); n := "";
			Gen(f, v, name, n, wr, var, x, y, max, first);
			d := Documents.dir.New(v, max, y)
		ELSE Dialog.ShowParamMsg("#Form:VariableNotFound", name, "", "")
		END;
		RETURN v
	END NewDialog;

	PROCEDURE Create*;
		VAR v: Views.View; i, j: INTEGER; mod, name: Files.Name; loc: Files.Locator; 
			w: FormViews.View; c: Containers.Controller;
	BEGIN
		v := NIL;
		IF new.link = "" THEN
			w := FormViews.dir.New(FormModels.dir.New()); c := w.ThisController();
			IF c # NIL THEN
				c.SetOpts({FormControllers.noFocus}) 
			ELSE
				w.SetController(FormControllers.dir.NewController({FormControllers.noFocus})) 
			END;
			v := w
		ELSE
			v := NewDialog(new.link)
		END;
		IF v # NIL THEN
			mod := new.link$; new.link := ""; name := "";
			StdCmds.CloseDialog;
			IF mod # "" THEN
				i := 0; WHILE (mod[i] # 0X) & (mod[i] # ".") DO INC(i) END;
				IF mod[i] # 0X THEN	(* module.variable *)
					mod[i] := 0X; INC(i); j := 0;
					WHILE mod[i] # 0X DO name[j] := mod[i]; INC(i); INC(j) END;
					name[j] := 0X
				END;
				StdDialog.GetSubLoc(mod, "Rsrc", loc, mod);
				IF name = "" THEN name := mod$ END;
				loc.res := 77
			ELSE
				loc := NIL; name := ""
			END;
			Views.Open(v, loc, name, NIL);
			Views.BeginModification(Views.notUndoable, v);
			Views.EndModification(Views.notUndoable, v)
		END
	END Create;
	
	PROCEDURE Empty*;
	BEGIN
		new.link := ""; Create
	END Empty;
	
	PROCEDURE CreateGuard* (VAR par: Dialog.Par);
	BEGIN
		IF new.link = "" THEN par.disabled := TRUE END
	END CreateGuard;

END FormGen.
