/* --- Copyright University of Sussex 1992.	 All rights reserved. ---------
 > File:		   C.all/lib/flavours/window_flavours.p
 > Purpose:		   a collection of classes for controlling PWM windows.
 > Author:		   Mark Rubinstein, Jul	 8 1986 (see revisions)
 > Documentation:  HELP * WINDOW_FLAVOURS
 > Related Files:
 */

section;

uses pwmrasterop;

;;; a hack which allows partwindows to have their operation selected instead
;;; of that of their host window.
vars select_graphic_paramaters = true;

;;; -- PWM_SELECT ---------------------------------------------------------
;;; A concession to the earlier PWM, which allows a more compact window
;;; selection in the methods defined below.

define pwm_select(win);
	lvars win;
	win -> pwm_selected;
	unless pwm_windowtype(win) == "gfx" then
		win -> pwmtextwindow;
	endunless;
enddefine;

;;; -- WINDOW_TYPE ---------------------------------------------------------
;;; a placeholder for both windows and pseudo-windows
flavour window_type a mixin isa named_object;
ivars name = '';
divars operation = PWM_SRC, paint = 1 /* black */;
	defmethod printself;
		printf('<%p %p>', [% myflavour<-name, name %]);
	enddefmethod;
	defmethod move_area(x1, y1, width, height, x2, y2);
	lvars x1 y1 width height x2 y2;
		^copy_area(x1, y1, width, height, PWM_CLR, x2, y2);
	enddefmethod;
	defmethod paintarea(operation) with_nargs 5;
	vars operation select_graphic_paramaters;
		^gfxselectself;
		false -> select_graphic_paramaters;
		^wipearea;
	enddefmethod;
	defmethod paintself(operation);
	vars operation select_graphic_paramaters;
		^gfxselectself;
		false -> select_graphic_paramaters;
		^wipeself;
	enddefmethod;
	defmethod clearself;
		^paintself(PWM_CLR);
	enddefmethod;
	defmethod window_raster;		;;; get the raster for the window
	lvars width height;
		explode(^size) -> height -> width;
		^area_raster(0, 0, width + 1, height + 1);
	enddefmethod;
	defmethod updaterof window_raster(raster);
	lvars raster;
		raster -> ^area_raster(0, 0);
	enddefmethod;
	defmethod circle(xcentre, ycentre, radius);
	lvars x y lasty xcentre ycentre radius rsquared = radius ** 2;
		0 -> lasty;
		for x from (xcentre - radius) + 1 to xcentre + radius do
			round(sqrt(rsquared - ((x - xcentre) ** 2))) -> y;
			^drawline([% x - 1, ycentre + lasty, x, ycentre + y %]);
			^drawline([% x - 1, ycentre - lasty, x, ycentre - y %]);
			y -> lasty;
		endfor;
	enddefmethod;
	defmethod lower_hemisphere(xcentre, ycentre, radius);
	lvars x y lasty xcentre ycentre radius rsquared = radius ** 2;
		0 -> lasty;
		for x from (xcentre - radius) + 1 to xcentre + radius do
			round(sqrt(rsquared - ((x - xcentre) ** 2))) -> y;
			^drawline([% x - 1, ycentre + lasty, x, ycentre + y %]);
			y -> lasty;
		endfor;
		^drawline([% xcentre - radius, ycentre, xcentre + radius, ycentre%]);
	enddefmethod;
	defmethod upper_hemisphere(xcentre, ycentre, radius);
	lvars x y lasty xcentre ycentre radius rsquared = radius ** 2;
		0 -> lasty;
		for x from (xcentre - radius) + 1 to xcentre + radius do
			round(sqrt(rsquared - ((x - xcentre) ** 2))) -> y;
			^drawline([% x - 1, ycentre - lasty, x, ycentre - y %]);
			y -> lasty;
		endfor;
		^drawline([% xcentre - radius, ycentre, xcentre + radius, ycentre%]);
	enddefmethod;
	defmethod filled_upper_hemisphere(xcentre, ycentre, radius);
	lvars x y xcenter ycentre radius rsquared = radius ** 2;
		for x from xcentre - radius to xcentre + radius do
			round(sqrt(rsquared - ((x - xcentre) ** 2))) -> y;
			^drawline([% x, ycentre - y, x, ycentre %]);
		endfor;
	enddefmethod;
	defmethod filled_lower_hemisphere(xcentre, ycentre, radius);
	lvars x y xcenter ycentre radius rsquared = radius ** 2;
		for x from xcentre - radius to xcentre + radius do
			round(sqrt(rsquared - ((x - xcentre) ** 2))) -> y;
			^drawline([% x, ycentre, x, ycentre + y %]);
		endfor;
	enddefmethod;
	defmethod filled_circle(xcentre, ycentre, radius);
	lvars x y xcenter ycentre radius rsquared = radius ** 2;
		for x from xcentre - radius to xcentre + radius do
			round(sqrt(rsquared - ((x - xcentre) ** 2))) -> y;
			^drawline([% x, ycentre - y, x, ycentre + y %]);
		endfor;
	enddefmethod;
	defmethod refreshself;
		;;; default method -- do nothing;
	enddefmethod;
	defmethod before refreshself;
		^clearself;
	enddefmethod;
endflavour;

;;; -- WINDOW --------------------------------------------------------------
flavour window a mixin isa window_type;
ivars myicon window_id = false;
	defmethod before initialise;
		^makeself(1, 1);			;;; make a small window by default.
		make_instance([icon mywindow ^self]) -> myicon;
	enddefmethod;
	defmethod after initialise;
		name -> myicon<-name;
	enddefmethod;
	defmethod killself;
		if window_id then
			pwm_kill_window(window_id);
			if pwm_selected == window_id then 0 -> pwm_selected endif;
			if pwmgfxsurface == window_id then
				pwmbasewindow -> pwmgfxsurface
			endif;
			false -> window_id;
		endif;
	enddefmethod;
	defmethod selectself;
		unless window_id do mishap('window not made', [^self]) endunless;
		unless pwm_selected == window_id do
			pwm_select(window_id);
		endunless;
	enddefmethod;
	defmethod after updaterof name;
		^selectself;
		name sys_>< '' -> pwm_windowlabel(pwm_selected);
	enddefmethod;
	defmethod position;
		^selectself;
		pwm_window_location(pwm_selected);
	enddefmethod;
	defmethod updaterof position(position);
	lvars position;
		^selectself;
		position -> pwm_window_location(pwm_selected);
	enddefmethod;
	defmethod size;
		^selectself;
		pwm_wininternalsize(pwm_selected);
	enddefmethod;
	defmethod updaterof size(s);
	lvars s;
		^selectself;
		s -> pwm_wininternalsize(pwm_selected);
	enddefmethod;
	defmethod iconic();
		^selectself;
		pwm_winopenstate(pwm_selected) == "closed";
	enddefmethod;
	defmethod updaterof iconic(closeit);
	lvars closeit;
		^selectself; pwm_selected;
		if closeit then pwm_close_window() else pwm_open_window() endif;
	enddefmethod;
	defmethod move;
		^selectself; pwm_move_window(pwm_selected);
	enddefmethod;
	defmethod expose;
		^selectself; pwm_expose_window(pwm_selected);
	enddefmethod;
	defmethod hide;
		^selectself; pwm_hide_window(pwm_selected);
	enddefmethod;
	defmethod resize;
		^selectself; pwm_resize_window(pwm_selected);
	enddefmethod;
	defmethod refresh;
		^selectself; pwm_refresh_window(pwm_selected);
	enddefmethod;
	defmethod copy_area(x1, y1, width, height, op, x2, y2);
	lvars x1 y1 width height op x2 y2;
		^gfxselectself;
		pwm_copy_raster(window_id, x1, y1, width, height, op,
			window_id, x2, y2);
	enddefmethod;
endflavour;

window_flavour <- subclass_responsibility("makeself");

;;; -- PARTIAL_RECEIVING_WINDOW --------------------------------------------
;;; this will window will get sent appropriate message about mouse and
;;; keyboards if it has a method to handle the messages.
flavour partial_receiving_window a mixin isa window;
	defmethod after makeself;
		;;; receive inputs if there is a method to handle it.
			window_input(% report_or_send(% self, myflavour, false %) %)
				-> pwm_itemhandler(window_id, false, false, false);
	enddefmethod;
	defmethod unrecognized_input(input);
	lvars input;
		mishap(input, 1, 'UNRECOGNIZED INPUT');
	enddefmethod;
	defmethod quit_requested;
	lvars prompt input;
		'QUIT WINDOW ' sys_>< name <> ' [YES] [YES] [NO]' -> prompt;
		repeat
			pwm_prompt_user(datalength(prompt) + 1, prompt) -> input;
			if subscrs(1, input) == `B` then
				if subscrs(2, input) < 35 then ^killself; endif;
				return;
			elseif subscrs(1, input) == `A` then
				if strmember(subscrs(2, input), 'yYNn') then
					if strmember(subscrs(2, input), 'Yy') then ^killself endif;
					return;
				endif;
			endif;
		endrepeat;
	enddefmethod;
endflavour;

;;; -- RECEIVING_WINDOW ----------------------------------------------------
;;; receiving windows will respond to all mouse event messages.	 The procedure
;;; for input will not make any check to see if it will respond to the message
;;; which should make it a bit more efficient.
flavour receiving_window a mixin isa window;
	defmethod after makeself;
		if window_id then
			window_input(% report_or_send(% self, myflavour, false %) %)
				-> pwm_itemhandler(window_id, false, false, false);
		endif
	enddefmethod;
endflavour;

receiving_window_flavour <- subclass_responsibility([left_button_pushed
	middle_button_pushed right_button_pushed left_button_released
	middle_button_released right_button_released mouse_exited window_opened
	window_closed nextchar]);

;;; -- TEXT_WINDOW ---------------------------------------------------------
flavour text_window isa window;
	defmethod makeself(width, height);
	lvars width height;
		unless window_id do
			pwm_make_txtwin(name, width, height) -> window_id;
			unless window_id then
				mishap('could not open self', [^self]);
			endunless;
		endunless;
	enddefmethod;
	defmethod updaterof nextchar(c);
	lvars c;
		pwm_selected;
		^selectself;
		rawcharout(c);
		rawoutflush();
		pwm_select();
	enddefmethod;
	defmethod writestring(s);
	lvars s;
		pwm_selected;
		^selectself;
		appdata(s, rawcharout);
		rawoutflush();
		pwm_select();
	enddefmethod;
endflavour;

;;; -- GRAPHICS_WINDOW -----------------------------------------------------
flavour graphics_window isa partial_receiving_window;
	defmethod gfxselectself;
		unless window_id do
			mishap('window not made', [^self]);
		endunless;
		window_id -> pwmgfxsurface;
		if select_graphic_paramaters then
			operation -> pwmrasterop;
			paint -> pwmpaintnum;
		endif;
	enddefmethod;
	defmethod makeself(width, height);
	lvars width height;
		unless window_id do
			pwm_make_gfxwin(name, width, height) -> window_id;
			unless window_id then
				mishap('could not open self', [^self]);
			endunless;
		endunless;
	enddefmethod;
	defmethod drawline with_nargs 1;
		^gfxselectself; pwm_draw_line();
	enddefmethod;
	;;; <- wipearea(left, top, width, height);
	defmethod wipearea with_nargs 4;
		^gfxselectself; pwm_wipe_area();
	enddefmethod;
	defmethod wipeself;
		^gfxselectself; ^wipearea(false);
	enddefmethod;
	defmethod area_raster(left, top, width, height);	;;; get raster for area
	lvars top left width height;
		^gfxselectself;
		make_instance([raster width ^width height ^height
			data_string % pwm_load_raster(left, top, width, height, 1) %]);
	enddefmethod;
	;;; either: raster -> object<- area_raster(left, top)
	;;; or:		string -> object <- area_raster(left, top, width, height)
	defmethod updaterof area_raster(raster, left, top);
	lvars left top raster width height;
		^gfxselectself;
		if isinstance(raster, raster_flavour) then
			pwm_dump_raster(left, top, raster<-width, raster<-height, 1,
				raster<-data_string);
		else
			top -> height;
			left -> width;
			raster -> top;
			-> left -> raster;
			unless isstring(raster) do
				mishap(raster, 1, 'RASTER NEEDED');
			endunless;
			pwm_dump_raster(left, top, width, height, 1, raster);
		endif;
	enddefmethod;
	;;; <- writetext(x, y, string)
	defmethod writetext with_nargs 3;
		^gfxselectself;
		pwm_draw_text();
	enddefmethod;
	;;; <- pixel(x, y)
	defmethod pixel;
		^gfxselectself;
		pwm_pixel();
	enddefmethod;
	defmethod updaterof pixel(x, y);
	lvars x y;
		^gfxselectself;
		-> pwm_pixel(x, y);
	enddefmethod;
endflavour;

define areas_overlap(x1, y1, w1, h1, x2, y2, w2, h2);
lvars x1 y1 x2 y2 w1 w2 h1 h2;
	max(x1, x2) < min(x1 + w1, x2 + w2)
		and
	max(y1, y2) < min(y1 + h1, y2 + h2)
enddefine;

;;; -- PARTIONED_WINDOW_TYPE --------------------------------------------------
;;; A window which hosts a collection of pseudo windows (part_windows).
flavour partitioned_window_type a mixin isa window_type collection;
	defmethod before killself;
		nil -> contents;
;;;			^appcontents(
;;;				procedure(p);
;;;				lvars p;
;;;					if p<-myflavour<-willrespondto("killself") then
;;;						p <- killself;
;;;					endif;
;;;				endprocedure);
	enddefmethod;
	defmethod parts_occupying(x, y);
	lvars p x y pos size;
		[%	for p in contents do
				p <- position -> pos;
				p <- size -> size;
				if x >= pos(1) and x <= pos(1) + size(1)
				and y >= pos(2) and y <= pos(2) + size(2) then
					p
				endif;
			endfor;
		%];
	enddefmethod;
	defmethod check_occupied(x, y);
	lvars x y p;
		if (^isoccupied(x, y) ->> p) then
			mishap('CO-ORDINATE (CORNER) OCCUPIED', [^x ^y ^p]);
		endif;
	enddefmethod;
	defmethod make_part(width, height, pfromleft, pfromtop) -> p;
	lvars width height pfromleft pfromtop p;
		make_instance([part_graphics_window hostwindow ^self position
			{% pfromleft, pfromtop %} size {%width, height%}]) -> p;
		^add(p);
	enddefmethod;
	defmethod report_mouse_event(x, y, event);
	lvars x y event part pos;
		for part in ^parts_occupying(x, y) do
			if part<-myflavour<-willrespondto(event) then
				part<-position -> pos;
				part(x - pos(1), y - pos(2), event);
			endif;
		endfor
	enddefmethod;
	defmethod updaterof report_mouse_event(v, x, y, event);
	lvars v x y event part pos;
		for part in ^parts_occupying(x, y) do
			if part <- myflavour <- willrespondto(event, "updater") then
				part<-position -> pos;
				v -> part(x - pos(1), y - pos(2), event);
			endif;
		endfor
	enddefmethod;
	defmethod updaterof nextchar(c);	;;; default -- do nothing
	lvars c;
	enddefmethod;
	defmethod windows_overlapping(win);
	lvars win x y h w window s p;
		explode(ivalof(win, "position")) -> y -> x;
		explode(ivalof(win, "size")) -> h -> w;
		[%	for window in contents do
				unless window == win do
					ivalof(window, "position") -> p;
					ivalof(window, "size") -> s;
					if areas_overlap(x, y, w, h, p(1), p(2), s(1), s(2)) then
						window
					endif;
				endunless;
			endfor; %]
	enddefmethod;
	defmethod refreshself;
		^appcontents(
			procedure(w);
				if w <- myflavour <- willrespondto("refreshself") then
					w <- refreshself;
				endif;
			endprocedure);
	enddefmethod;
endflavour;

;;; set default values for the various mouse events
applist([left_button_pushed right_button_pushed middle_button_pushed
	middle_botton_released left_button_released right_button_released],
	procedure(e);
	lvars e pdr;
		procedure;
			^report_mouse_event(e)
		endprocedure -> pdr;
		"partitioned_window_type" <> "<-" <> e -> pdprops(pdr);
		pdr -> partitioned_window_type_flavour <- methodfor(e);
	endprocedure);

applist([window_opened window_closed],
	procedure(e);
	lvars e pdr;
		procedure; endprocedure -> pdr;
		"partitioned_window" <> "<-" <> e -> pdprops(pdr);
		pdr -> partitioned_window_type_flavour <- methodfor(e);
	endprocedure);


;;; -- PARTIONED_WINDOW -------------------------------------------------------
;;; A window which hosts a collection of pseudo windows (part_windows).
flavour partitioned_window isa graphics_window partitioned_window_type receiving_window;
lvars moving_part_window = false;
	defmethod before updaterof size(v);
	lvars v, ov = ^size;
		{% max(v(1), ov(1)), max(v(2), ov(2)) %}
	enddefmethod;
	defmethod middle_button_pushed(x, y);
	lvars x y p;
		unless (^parts_occupying(x, y) ->> p) == nil do
			hd(p )-> moving_part_window;		;;; only move one
			pwm_selected;
			^selectself;
			pwmtxtcursor -> pwm_windowcursor(pwm_selected);
			pwm_select();
		endunless;
	enddefmethod;
	defmethod mouse_exited;
		if moving_part_window then
			pwm_selected;
			^selectself;
			pwmstdcursor -> pwm_windowcursor(pwm_selected);
			false -> moving_part_window;
			pwm_select();
		endif;
	enddefmethod;
	defmethod middle_button_released(x, y);
	lvars x y wins s = ^size;
		if moving_part_window then
			^windows_overlapping(moving_part_window) -> wins;
			min(x, s(1) - (1 + (moving_part_window<-size)(1))) -> x;
			min(y, s(2) - (1 + (moving_part_window<-size)(2))) -> y;
			{^x ^y} -> moving_part_window <- position;
			pwm_selected;
			^selectself;
			pwmstdcursor -> pwm_windowcursor(pwm_selected);
			pwm_select();
			unless wins == nil do
				for x in wins do x <- refreshself endfor;
				moving_part_window <- refreshself;
			endunless;
			false -> moving_part_window;
		endif;
	enddefmethod;
endflavour;

define check_coord(c, max_c);
lvars c max_c;
	if c < 0 or c > max_c then
		mishap('CO-ORD OUT OF BOUNDS', [^c should lie between 0 and ^max_c]);
	endif;
enddefine;

define host_equiv_coord(c, max_c, c_offset);
lvars c max_c c_offset;
	check_coord(c, max_c);
	c +	 c_offset;
enddefine;

flavour part_window isa window_type ivalofinit;
ivars char_height = 16, char_width = 8, char_base = 4;
divars hostwindow position = {1 1}, size = {100 100};
	defmethod check_xcoord with_nargs 1; check_coord(size(1)) enddefmethod;
	defmethod check_ycoord with_nargs 1; check_coord(size(2)) enddefmethod;
	defmethod host_equiv_x(c);
	lvars c;
		host_equiv_coord(c, (^size)(1), position(1))
	enddefmethod;
	defmethod host_equiv_y(c);
	lvars c;
		host_equiv_coord(c, (^size)(2), position(2))
	enddefmethod;
	defmethod after initialise;
		unless isinstance(hostwindow, partitioned_window_type_flavour) do
			make_instance([partitioned_window
				name % gensym("partitioned_window") %
				size {% size(1) + 50, size(2) + 50 %}])
				-> hostwindow;
		endunless;
		hostwindow <- add(self);
	enddefmethod;
	defmethod killself;
		hostwindow <- remove(self);
	enddefmethod;
	defmethod before updaterof position(newp) -> newp;
	lvars newp;
		hostwindow <- move_area(position(1), position(2),
			size(1) + 1, size(2) + 1, newp(1), newp(2));
	enddefmethod;
	defmethod apply_area(x, y, width, height, host_message);
	lvars x y width height host_message;
	vars select_graphic_paramaters = false;
		if x + width > size(1) then size(1) - x -> width endif;
		if y + height > size(2) then size(2) - y -> height endif;
		^gfxselectself;
		hostwindow(^host_equiv_x(x), ^host_equiv_y(y),
			width, height, host_message);
	enddefmethod;
	defmethod copy_area(x1, y1, width, height, op, x2, y2);
	lvars x1 y1 width height op x2 y2 ;
		min(size(1), x1 + width) -> width;
		min(size(2), y1 + height) -> height;
		hostwindow <- copy_area(^host_equiv_x(x1), ^host_equiv_y(y1),
			width, height, op, ^host_equiv_x(x2), ^host_equiv_y(y2));
	enddefmethod;
endflavour;
part_window_flavour <- subclass_responsibility("refreshself");

vars bordering = true;
flavour part_graphics_window isa part_window;
	defmethod gfxselectself;
		if select_graphic_paramaters then
			operation -> pwmrasterop;
			paint -> pwmpaintnum;
		endif;
	enddefmethod;
	defmethod drawline(l);
	lvars l save = 1, t;
	vars select_graphic_paramaters;
		if isinteger(l) then
			repeat l times
				if isinteger(subscr_stack(save) ->> t) then
					^host_equiv_x(t) -> subscr_stack(save);
					save + 1 -> save;
					^host_equiv_y(subscr_stack(save)) -> subscr_stack(save);
				else
					^host_equiv_x(t(1)) -> t(1);
					^host_equiv_y(t(2)) -> t(2);
					t -> subscr_stack(save)
				endif;
				save + 1 -> save
			endrepeat;
		else
			;;; massage the list;
			l -> save;
			until save == nil do
				^host_equiv_x(hd(save)) -> hd(save);
				^host_equiv_y(hd(tl(save))) -> hd(tl(save));
				tl(tl(save)) -> save;
			enduntil;
		endif;
		^gfxselectself;
		false -> select_graphic_paramaters;
		hostwindow <- drawline(l);
	enddefmethod;
	defmethod borderself;
		^drawline([% 0, 0, size(1), 0, size(1), size(2), 0, size(2), 0, 0 %]);
	enddefmethod;
	defmethod wipearea with_nargs 4; ^apply_area("wipearea"); enddefmethod;
	defmethod wipeself;
		hostwindow <- wipearea(position(1), position(2), size(1) + 1,
			size(2) + 1);
	enddefmethod;
	defmethod area_raster with_nargs 4; ^apply_area("area_raster") enddefmethod;
	defmethod updaterof area_raster(raster, x, y);
	lvars x y;
		raster -> hostwindow <- area_raster(^host_equiv_x(x),
			^host_equiv_y(y));
	enddefmethod;
	defmethod writetext(x, y, str);
	lvars x y str;
		min(x, size(1) - (char_width * datalength(str))) -> x;
		min(size(2), max(y, char_height - char_base)) -> y;
		hostwindow <- writetext(^host_equiv_x(x), ^host_equiv_y(y), str);
	enddefmethod;
	defmethod pixel(x, y);
	lvars x y;
		hostwindow <- pixel(^host_equiv_x(x), ^host_equiv_y(y));
	enddefmethod;
	defmethod updaterof pixel(x, y);
	lvars x y;
		-> hostwindow <- pixel(^host_equiv_x(x), ^host_equiv_y(y));
	enddefmethod;
	defmethod after refreshself;
		if bordering then self <- borderself endif;
	enddefmethod;
endflavour;

;;; make uses happy
vars window_flavours = true;

endsection;

/* --- Revision History ---------------------------------------------------
--- Gareth Palmer, Sep  7 1989 - Altered for new names:
		pwm_makegfxwin          -> pwm_make_gfxwin
		pwm_killwindow      	-> pwm_kill_window
		pwm_maketxtwin          -> pwm_make_txtwin
		pwm_setwincursor        -> pwm_windowcursor    (updater of)
		pwm_win_internalsize    -> pwm_wininternalsize
		pwm_win_openstate       -> pwm_winopenstate
		pwm_window_label        -> pwm_windowlabel
		pwm_gfxcopyraster       -> pwm_copy_raster
		pwm_gfxdrawline         -> pwm_draw_line
		pwm_gfxpixel            -> pwm_pixel
		pwm_gfxwipearea         -> pwm_wipe_area
		pwmgfxpaintnum          -> pwmpaintnum
		pwmgfxrasterop          -> pwmrasterop
		pwm_gfxtext             -> pwm_draw_text
		pwm_gfxdumpraster       -> pwm_dump_raster
		pwm_gfxloadraster       -> pwm_load_raster
		pwm_promptuser          -> pwm_prompt_user
		pwmitemhandler          -> pwm_itemhandler
--- Poplog System, Sep 24 1987 (Ian Rogers)
	added before updaterof size demon in partitioned_window flavour so that
	window only grows, never shrinks.
	Removed uses window_input and uses icon_flavour as they are
	autoloadable
--- Nic Ford, Aug 20 1987 - added the "uses window_input" and
			"uses icon_flavour" to replace the strange
			"compile('~ianr/pwm/icon_flavour')" which had appeared from
			somewhere.
--- Ian Rogers - Nic Ford, Jul 20-21 1987
	Changed all old style (V12) PWM procedures to new style (V13) equivalents
	(That was not as easy as it sounds)
 */
