[comp.lang.pascal] Units -- GWin

gt3070b@prism.gatech.EDU (Jeff Watkins) (05/30/90)

unit GWin;
interface
const
	LockSize=1;
	LockOpen=2;
	LockPos=4;
type
	CapPtr=		^Capsule;
	procPtr=	Procedure(C:CapPtr);
	Capsule=	object
		w,h:	integer;
		Fresh:	boolean;
		Title:	string[40];
		end;

Function	NewProcess(w,h:integer;A:byte;Proc,Ref:ProcPtr;T:string):byte;
Procedure	KillProcess(Cap:byte);
Procedure	CheckProcess;
Function	ProcessDone(Cap:byte):boolean;
Procedure	NulProcess(C:CapPtr);
Procedure	NulRefresh(C:CapPtr);
Function	AllDone:boolean;


implementation
uses gutil,mouse,GMenu,Graph,dos,Fonts;
const
	NumCapsules=	50;
type
	WindowPtr= ^Window;

	Window=	object(Capsule)
{		Pmenu:	menuptr;}
		x,y:	integer;
		attr:	byte;
		drawn:	boolean;

		LineS:	LineSettingsType;
		TextS:	TextSettingsType;
		Point:	PointType;
		Next:	WindowPtr;
		Prev:	WindowPtr;
		Process:	ProcPtr;
		Refresh:		ProcPtr;

		procedure	Redraw;
		procedure	DrawAll;
		constructor	Init(wx,wy,ww,wh:word;a:byte;FN:string);
		procedure	SetTitle(T:string);

		destructor	Done;
		procedure	SetActive;
		procedure	SetView;
		procedure	Size;
		procedure	Move;
		procedure	DrawCovered;
		procedure	DrawCovering;
		procedure	SaveSettings;
		procedure	SetProc(Proc,Ref:ProcPtr);
		procedure	SetAttr(LOpen,LSize,LPos:boolean);
		function	Event(mxx,myy:integer;but1,but2,but3:boolean):boolean;
		function	AllClosed:boolean;
		function	Covers(W1:Window):boolean;
		function	Covered:boolean;
		function	Covering:boolean;
		procedure	Check;
		end;

Var
	Active:		WindowPtr;
	oldmin:		word;
	oldhrs:		word;
	Count:		longint;
	SavePtr:	Pointer;
	Clock:		Window;
	gd,gm:		integer;
	Capsules:	array[0..NumCapsules] of Window;

Procedure	Window.SetProc(Proc,Ref:ProcPtr);
begin
	Process:=Proc;
	Refresh:=Ref;
end;

procedure	Window.Redraw;
var
	TS:	TextSettingsType;
begin
	SetViewPort(0,0,MaxX,MaxY,true);
	if (attr and LockPos)<>LockPos then
	begin
		VertScroll(x,y+15,y+h-16);
		HorizScroll(x+15,y+h-15,x+w-1);
		VBar(x,y+15,y+h-16,0,(h-64)/MaxY);
		HBar(x+15,y+h-15,x+w-1,0,(w-64)/MaxX);
		UBox(x,y+h-15,x+14,y+h-1);
		UBox(x+15,y+15,x+w-1,y+h-16);
	end
	else
		UBox(x,y+15,x+w-1,y+h-1);
	if (attr and LockOpen)<>LockOpen then
	begin
		UBox(x,y,x+14,y+14);
		UBox(x+15,y,x+w-1,y+14);
		DBox(x+2,y+2,x+12,y+12);
	end
	else
		UBox(X,y,x+w-1,y+14);
	gettextsettings(TS);
	setcolor(8);
	SetTextStyle(SmallFont,HorizDir,0);
	SetTextJustify(CenterText,TopText);
	if (attr and LockOpen)=LockOpen then
	begin
		SetViewPort(x+1,y,x+w-2,y+16,true);
		hidem;
		OutTextXY(w div 2,2,title);
		showm;
	end
	else
	begin
		setViewPort(x+16,y,x+w-2,y+16,true);
		hidem;
		OutTextXY((w-16) div 2,2,title);
		showm;
	end;
	SetView;
	with ts do
	begin
		setTextStyle(Font,Direction,CharSize);
		SetTextJustify(Horiz,Vert);
	end;
	fresh:=false;
	drawn:=true;
end;

procedure	Window.SaveSettings;
begin
	GetTextSettings(TextS);
	GetLineSettings(Lines);
	Point.x:=GetX;
	Point.y:=GetY;
end;

procedure	Window.SetView;
begin
	if (attr and LockPos)=LockPos then
		SetViewPort(x+1,y+16,x+w-2,y+h-2,true)
	else
		SetViewPort(x+16,y+16,x+w-2,y+h-17,true);
	with TextS do
	begin
		SetTextStyle(Font,Direction,CharSize);
		SetTextJustify(Horiz,Vert);
	end;
	with Lines do
		SetLineStyle(LineStyle,Pattern,Thickness);
	with Point do
		MoveTo(x,y);
end;

procedure	Window.SetActive;
begin
	if Active=\@self then
		exit;
	if Prev<>Nil then
		Prev^.Next:=Next;
	if (Next<>nil) and (Prev<>Nil) then
		Next^.Prev:=Prev;
	if Active<>Nil then
		Next:=Active;
	Prev:=Nil;
	if active<>Nil then
		Active^.SaveSettings;
	Redraw;
	SetView;
	if active<>nil then
		Active^.Prev:=\@Self;
	Active:=\@Self;
end;

Destructor	Window.Done;
begin
{	KillMenu(PMenu);}
	hidem;
	setViewPort(0,0,MaxX,MaxY,true);
	setcolor(0);
	setfillstyle(1,0);
	bar(x,y,x+w-1,y+h-1);
	showm;
	if covered then
		DrawCovering;
	if covering then
		DrawCovered;
	DrawCovered;
	if Active<>\@Self then
	begin
		if prev<>nil then
			Prev^.Next:=Next;
		if Next<>nil then
			Next^.Prev:=Prev;
	end
	else
	begin
		Active:=Nil;
		if Next<>Nil then
		begin
			Next^.Prev:=nil;
			Next^.SetActive;
		end;
		showm;
	end;
	x:=-1;
end;

{$F+}
procedure	NulRefresh(C:CapPtr);
begin
	setcolor(random(16));
	lineto(random(C^.w),Random(C^.h));
end;

Procedure	NulProcess(C:CapPtr);
begin
	C^.Fresh:=false;
	inc(Count);
end;
{$F-}

procedure	Window.SetAttr(LOpen,LSize,LPos:boolean);
begin
	if LOpen then
		attr:=attr or LockOpen;
	if LSize then
		attr:=attr or LockSize;
	if LPos then
		attr:=attr or LockPos;
end;

Constructor	Window.Init(wx,wy,ww,wh:word;A:byte;fn:string);
begin
	Title:='';
	attr:=a;
	x:=wx;
	y:=wy;
	w:=ww;
	h:=wh;
	Process:=NulProcess;
	Refresh:=NulRefresh;

	Texts.Font:=SmallFont;
	TextS.Direction:=HorizDir;
	TextS.charSize:=0;
	Point.x:=0;
	Point.y:=0;
	drawn:=false;
	Prev:=Nil;
	Next:=Active;
	Fresh:=false;
	SetActive;
{	PMenu:=LoadMenu(FN);}
end;

function	Window.Covering:boolean;
var
	w1:	windowPtr;
	C:	boolean;
begin
	C:=false;
	w1:=\@Self;
	while (w1^.next<>nil) and not C do
	begin
		w1:=w1^.next;
		if	(w1^.x-x<w) and (x<w1^.x+w1^.w) and
			(w1^.y-y<h) and (y<w1^.y+w1^.h) then
				C:=true;
	end;
	Covering:=C;
end;

function	Window.Covers(w1:Window):boolean;
begin
	covers:=false;
	if (w1.x=x) and (w1.w=w) and (w1.h=h) and (w1.y=y) then
		exit;
	if	(w1.x-x<w) and (x<w1.x+w1.w) and
		(w1.y-y<h) and (y<w1.y+w1.h) then
		Covers:=true;
end;

function	Window.Covered:boolean;
var
	w1:	windowPtr;
	C:	boolean;
begin
	C:=false;
	w1:=\@Self;
	if w1=nil then
		exit;
	while (w1^.prev<>nil) and not C do
	begin
		w1:=w1^.prev;
		if	(w1^.x-x<w) and (x<w1^.x+w1^.w) and
			(w1^.y-y<h) and (y<w1^.y+w1^.h) and
			(w1<>\@Self) then
				C:=true;
	end;
	Covered:=C;
end;

function	Window.Event(mxx,myy:integer;but1,but2,but3:boolean):boolean;
begin
	Process(\@Self);
	if not drawn then
		if (Active=\@Self) then
			redraw
		else
			SetActive;
	if ((Active=\@Self) or not Covered) and (Not Fresh) then
	begin
		if (x-mxx<16-4*(4-(Attr and LockPos))) and (mxx<x+w-1) and
			(y-myy<0) and (myy<y+h-1-4*(4-(Attr and LockPos))) then
			Hidem;
		SetView;
		Refresh(\@Self);
		SaveSettings;
		if (x-mxx<16-4*(4-(Attr and LockPos))) and (mxx<x+w-1) and
			(y-myy<0) and (myy<y+h-1-4*(4-(Attr and LockPos))) then
			Showm;
	end;
	Event:=false;
	if (mxx>x) and (mxx<x+w-1) and
		(myy>y) and (myy<y+h-1) then
	begin
		event:=true;
		if but1 then
		begin
			if (Active<>\@Self) then
				SetActive;
			exit;
		end;
{		if but2 then
		begin
			if (Active<>\@Self) then
				SetActive;
			case Menu(PMenu,mxx,myy) of
				0: Done;
			end;
			exit;
		end;}
		if (myy<y+15) and (mxx>x+14) and but3 then
		begin
			if (Active<>\@Self) then
				SetActive;
			Move;
			exit;
		end;
		if (mxx<x+15) and (myy<y+15) and but3 then
		begin
			if (attr and LockOpen)<>LockOpen then
				Done;
			exit;
		end;
		if	(mxx>x) and (myy>y+14) and (myy<y+h-2) and
			((attr and LockSize)<>LockSize) and but3 then
		begin
			if (Active<>\@Self) then
				SetActive
			else
				SetView;
			Size;
			exit;
		end;
		event:=false;
	end;
end;

procedure	Window.DrawAll;
var
	w1:	windowPtr;
begin
	w1:=\@Self;
	if w1=nil then exit;

	while w1^.next<>nil do
		w1:=w1^.next;
	while w1<>nil do
	begin
		w1^.drawn:=false;
		w1:=w1^.prev;
	end;
end;

procedure	Window.DrawCovered;
var
	w1:	WindowPtr;
begin
	if not covering and not covered then
		exit;
	w1:=\@self;
	while w1^.next<>nil do
		w1:=w1^.next;
	while w1<>nil do
	begin
		if Covers(w1^) then
		begin
			w1^.drawn:=false;
		end;
		if (W1^.Covers(Self)) then
		begin
			w1^.drawn:=false;
		end;
		w1:=w1^.prev;
	end;
end;

procedure	Window.DrawCovering;
var
	w1:	WindowPtr;
begin
	if not covering and not covered then
		exit;
	w1:=\@self;
	while w1^.next<>nil do
		w1:=w1^.next;
	while w1<>nil do
	begin
		if (W1^.Covers(Self)) or (covers(w1^)) then
		begin
			w1^.drawn:=false;
		end;
		w1:=w1^.prev;
	end;
end;

procedure	Window.Move;
var
	b:		boolean;
	ox:		integer;
	oy:		integer;
	mxx:	integer;
	myy:	integer;
	Ln:		LineSettingsType;
	w2:		integer;
	h2:		integer;
begin
	b:=but3;
	ox:=mx;
	oy:=my;
	w2:=w div 2;
	h2:=h div 2;
	if ox-w2<0 then
		ox:=w2;
	if ox+w2>MaxX then
		ox:=MaxX-w2;
	if oy-h2<0 then
		oy:=h2;
	if oy+h2>MaxY then
		oy:=MaxY-h2;
	GetLineSettings(Ln);
	SetLineStyle(DashedLn,1,1);
	SetViewPort(0,0,MaxX,MaxY,true);
	SetWriteMode(XorPut);
	hidem;
	rectangle(ox-w2,oy-h2,ox+w2-1,oy+h2-1);
	showm;
	repeat
		mxx:=mx;
		myy:=my;
		if mxx-w2<0 then
			mxx:=w2;
		if mxx+w2>MaxX then
			mxx:=MaxX-w2;
		if myy-h2<0 then
			myy:=h2;
		if myy+h2>MaxY then
			myy:=MaxY-h2;
		if (ox<>mxx) or (oy<>myy) then
		begin
			hidem;
			rectangle(ox-w2,oy-h2,ox+w2-1,oy+h2-1);
			rectangle(mxx-w2,myy-h2,mxx+w2-1,myy+h2-1);
			showm;
			ox:=mxx;
			oy:=myy;
		end;
	until but3<>b;
	SetLineStyle(SolidLn,1,1);
	setwriteMode(CopyPut);
	hidem;
	setcolor(0);
	setfillstyle(1,0);
	bar(x,y,x+w-1,y+h-1);
	showm;
	DrawCovered;
	x:=ox-w2;
	y:=oy-h2;
	redraw;
	SetView;
	with Ln do
		SetLineStyle(LineStyle,Pattern,Thickness);
	Fresh:=false;
end;

procedure	Window.Size;
var
	b:		boolean;
	ox:		word;
	oy:		word;
	mxx:	word;
	myy:	word;
	Vw:		ViewPortType;
	Ln:		LineSettingsType;
begin
	b:=but3;
	ox:=mx;
	oy:=my;
	GetLineSettings(Ln);
	GetViewSettings(Vw);
	SetLineStyle(DashedLn,1,1);
	SetViewPort(0,0,MaxX,MaxY,true);
	SetWriteMode(XorPut);
	hidem;
	rectangle(vw.x1,vw.y1,ox,oy);
	showm;
	repeat
		mxx:=mx;
		myy:=my;
		if mxx<x+80 then
			mxx:=x+80;
		if myy<y+80 then
			myy:=y+80;
		if (ox<>mxx) or (oy<>myy) then
		begin
			hidem;
			rectangle(Vw.X1,Vw.y1,ox,oy);
			rectangle(Vw.x1,Vw.y1,mxx,myy);
			showm;
			ox:=mxx;
			oy:=myy;
		end;
	until but3<>b;
	SetLineStyle(SolidLn,1,1);
	setwriteMode(CopyPut);
	hidem;
	setcolor(0);
	setfillstyle(1,0);
	bar(x,y,x+w-1,y+h-1);
	showm;
	drawCovered;
	w:=mxx-x+1;
	h:=myy-y+1;
	if ((attr and LockPos)<>LockPos) and (y+h-1<MaxY) then
		h:=h+15;
	redraw;
	SetView;
	with Ln do
		SetLineStyle(LineStyle,Pattern,Thickness);
	Fresh:=False;
end;

Function	Window.AllClosed:boolean;
var
	w1:	windowPtr;
begin
	AllClosed:=true;
	w1:=\@Self;
	while (w1<>nil) and ((w1^.attr and LockOpen)=LockOpen) do
		w1:=w1^.next;
	if w1<>nil then
		Allclosed:=false;
end;

procedure	Window.Check;
var
	W1:		WindowPtr;
	mxx:	integer;
	myy:	integer;
	b1,
	b2,
	b3:		boolean;
begin
	b1:=but1;
	b2:=but2;
	b3:=but3;
	mxx:=mx;
	myy:=my;
	W1:=\@Self;
	while (W1<>Nil) and not W1^.Event(mxx,myy,b1,b2,b3) do
		W1:=W1^.Next;
end;

procedure	Window.SetTitle(T:String);
begin
	title:=T;
	if Active<>\@Self then
		SetActive
	else
		Redraw;
end;

{$F+}
procedure	ProcessClock(C:CapPtr);
var
	h,m,s,s100:	word;
begin
	if not C^.Fresh then
		exit;
	C^.Fresh:=true;
	GetTime(h,m,s,s100);
	if (oldMin<>m) or (oldhrs<>h) then
		C^.Fresh:=false;
end;

procedure	RefreshClock(C:CapPtr);
var
	Points:		array[0..3] of PointType;
	h,m,s,s100:	word;
	x,y:		word;
	width:		word;
	height:		word;
	Arc1:		ArcCoordsType;
	Arc2:		ArcCoordsType;
	A:			word;
begin
	x:=70;
	y:=80;
	GetTime(h,m,s,s100);
	hidem;
	setwritemode(copyput);
	setFillStyle(1,7);
	setcolor(7);
	A:=90-30*oldhrs-oldmin div 2;
	Arc(x,y,A-5,A+5,35);
	GetArcCoords(Arc1);
	Arc(x,y,A-15,A+15,12);
	GetArcCoords(Arc2);
	with Arc1 do
	begin
		Points[1].x:=XStart;
		Points[1].y:=YStart;
		Points[0].x:=XEnd;
		Points[0].y:=YEnd;
	end;
	with Arc2 do
	begin
		Points[2].x:=XStart;
		Points[2].y:=YStart;
		Points[3].x:=XEnd;
		Points[3].y:=YEnd;
	end;
	FillPoly(4,Points);
	A:=90-6*oldmin;
	Arc(x,y,A-5,A+5,45);
	GetArcCoords(Arc1);
	Arc(x,y,A-10,A+10,12);
	GetArcCoords(Arc2);
	with Arc1 do
	begin
		Points[1].x:=XStart;
		Points[1].y:=YStart;
		Points[0].x:=XEnd;
		Points[0].y:=YEnd;
	end;
	with Arc2 do
	begin
		Points[2].x:=XStart;
		Points[2].y:=YStart;
		Points[3].x:=XEnd;
		Points[3].y:=YEnd;
	end;
	FillPoly(4,Points);
	oldhrs:=h;
	oldmin:=m;
	setcolor(8);
	SetFillStyle(1,8);
	SetTextStyle(TriplexFont,HorizDir,0);
	SetTextJustify(CenterText,CenterText);
	OutTextXY(x,y-68,'12');
	OutTextXY(x+60,y,'3');
	OutTextXY(x-60,y,'9');
	OutTextXY(x,y+60,'6');
	SetColor(15);
	Arc(x,y,45,225,49);
	Arc(x,y,45,225,10);
	SetColor(8);
	Arc(x,y,226,44,49);
	Arc(x,y,226,44,10);
	C^.Fresh:=true;
	A:=90-30*oldhrs-oldmin div 2;
	Arc(x,y,A-5,A+5,35);
	GetArcCoords(Arc1);
	Arc(x,y,A-15,A+15,12);
	GetArcCoords(Arc2);
	with Arc1 do
	begin
		Points[1].x:=XStart;
		Points[1].y:=YStart;
		Points[0].x:=XEnd;
		Points[0].y:=YEnd;
	end;
	with Arc2 do
	begin
		Points[2].x:=XStart;
		Points[2].y:=YStart;
		Points[3].x:=XEnd;
		Points[3].y:=YEnd;
	end;
	FillPoly(4,Points);
	A:=90-6*(oldmin);
	Arc(x,y,A-5,A+5,45);
	GetArcCoords(Arc1);
	Arc(x,y,A-10,A+10,12);
	GetArcCoords(Arc2);
	with Arc1 do
	begin
		Points[1].x:=XStart;
		Points[1].y:=YStart;
		Points[0].x:=XEnd;
		Points[0].y:=YEnd;
	end;
	with Arc2 do
	begin
		Points[2].x:=XStart;
		Points[2].y:=YStart;
		Points[3].x:=XEnd;
		Points[3].y:=YEnd;
	end;
	FillPoly(4,Points);
	showm;
end;

procedure	Close;
begin
	Clock.Done;
	closeGraph;
	restoreCRTMode;
	ExitProc:=SavePtr;
end;
{$F-}

Function	NewProcess(w,h:integer;A:byte;Proc,Ref:ProcPtr;T:string):byte;
var
	c:	byte;
begin
	for c:=0 to NumCapsules do
		if Capsules[c].x=-1 then
		begin
			Capsules[c].Init((MaxX-w) div 2,(MaxY-h) div 2,w,h,A,'');
			Capsules[C].SetTitle(T);
			Capsules[C].SetProc(Proc,Ref);
			NewProcess:=c;
			exit;
		end;
	halt(50);
end;

Function	AllDone:boolean;
begin
	AllDone:=Active^.AllClosed;
end;

procedure	CheckProcess;
begin
	Active^.Check;
end;

function	ProcessDone(Cap:byte):boolean;
begin
	ProcessDone:=Capsules[cap].x=-1;
end;

Procedure	KillProcess(Cap:byte);
begin
	Capsules[cap].Done;
	Capsules[cap].x:=-1;
end;

var
	Ccnt:	word;
begin
	for ccnt:=0 to NumCapsules do
		Capsules[ccnt].x:=-1;
	Active:=nil;
	SelectColor:=3;
	gd:=detect;
	initgraph(gd,gm,'/bin/graphics');
	gm:=getMaxMode;
	initgraph(gd,gm,'/bin/graphics');
	Setup;
	SetBkColor(0);
	InitGm;
	if (MaxX<639) or (MaxY<349) then
	begin
		CloseGraph;
		RestoreCRTMode;
		writeln('This program requires an EGA, ATT400, MCGA, VGA,');
		writeln('or IBM 8514A video adapter card to operate.');
		halt(1);
	end;

	Clock.Init(0,MaxY-176,143,176,LockPos+LockSize+LockOpen,'');
	Clock.SetTitle('Clock');
	Clock.SetProc(ProcessClock,RefreshClock);
	SavePtr:=ExitProc;
	ExitProc:=\@Close;
end.

-- 
Jeff Watkins  gt3070b@prism.gatech.edu
"All opinions are mine... so don't even think of keeping some to yourself!"