%donald
viewport view
#	The following definitions define a room ...
#	... and some objects inside the room.
#

# The room is rectangle in shape.

int	width, length		# the dimension of room
point   NW, NE, SW, SE		# the 4 corners of room
line    N1, N2, S, E, W		# the 4 walls of room
                                # North wall composites of 2 walls & a door

				### Every room has a door ###
openshape door			# declare the door

within door {
        point   hinge, lock	# a door has a hinge, and a lock
        line    door		# the door itself
	int	width		# the size of the door
        boolean open		# use it as a flag, telling whether ...
				# ... the door has opened
        door = [hinge, lock]

        lock = hinge + (if open then {0, -width} else {width, 0})
}

within door {
	hinge = ~/NW + {15, -10}	# set the coordinate of the hinge
	open = true			# the door has opened
	width = 200			# the size of the door
}

N1 = [NW, {door/hinge.1, NW.2}]
N2 = [{door/hinge.1+door/width, NW.2}, NE]
S = [SW, SE]
W = [NW, SW]
E = [NE, SE]

SW = {100, 100}
SE = SW + {width, 0}		# The other 3 corners are relative
NE = SW + {width, length}	# to South-West corner.
NW = SW + {0, length}		#

width, length = 800, 800	# 800*800 pts

###########################################################################
openshape table			# There is a table inside the room.

within table {
        int     width, length		# the dimension of table
        point   NW, NE, SW, SE		# the 4 corners of table
        line    N, S, E, W		# the 4 sides of table

        N = [NW, NE]
        S = [SW, SE]
        W = [NW, SW]
        E = [NE, SE]

        SE = SW + {width, 0}		# the other 3 corners are
        NE = SW + {width, length}	# relative to SW corner
        NW = SW + {0, length}		#

	##### table/lamp #####

        openshape lamp			# There is a lamp on the table
	within lamp {
        	point	centre		# center of the table
		int	size		# size of the lamp
		int	half		# half of size
		circle	base

		size = 50
		half = size div 2
        	centre = (~/SW + ~/NE) div 2	# at the centre of table

					# L1-L8 forms an octagon.
		line	L1, L2, L3, L4, L5, L6, L7, L8

		L1 = [centre + {size, -half}, centre + {size, half}]
		L2 = [L1.2, centre + {half, size}]
		L3 = [L2.2, centre + {-half, size}]
		L4 = [L3.2, centre + {-size, half}]
		L5 = [L4.2, centre + {-size, -half}]
		L6 = [L5.2, centre + {-half, -size}]
		L7 = [L6.2, centre + {half, -size}]
		L8 = [L7.2, L1.1]
		base = circle(centre, size * 1.25)
	}
}

within table {
		# let the size of table be 300*300 pts.
	width, length = 300, 300

		# place the SW of table at the center of the room.
	SW = (~/SW + ~/NE) div 2
}

###########################################################################
point	plug
point	plug1, plug2		# there are 2 plugs.
plug1 = (S.1+S.2) div 2		# middle of South wall
plug2 = (E.1+E.2) div 2		# middle of East wall

line	cable			# cable connects the table/lamp and the plug
int	cablelength
cable = [plug, table/lamp/centre]
plug = plug1			# let cable connects to plug1
cablelength = 600
#
# Now set the line style of cable be dotted line.
#   Because many Donald commands hasn't implemented,
#	I just directly access Eden using the non-standard `?' command.
? A_cable = "linestyle=dashed,dash=13";


###########################################################################

openshape desk			# there is a desk in the room

within desk {
        int     width, length		# the size of the desk
        point   NW, NE, SW, SE		# the 4 corners of the desk
        line    N, S, E, W		# the 4 edges of the desk

        N = [NW, NE]
        S = [SW, SE]
        W = [NW, SW]
        E = [NE, SE]

	width, length = 250, 350

		# initially the desk is placed at (100,100) of the room.
        SW = ~/SW + {15, 15}
        SE = SW + {width, 0}		# the other 3 corners are ...
        NW = SW + {0, length}		# ... relative to SW corner
        NE = NW + {width, 0}		#

	##### desk/drawer #####

        openshape drawer	# the desk has a drawer

        within drawer {
		int     k	# k --	a parameter describes
				#	the condition of drawer
				# 		1 --> closed
				#		larger k --> more open

                int     width, length	# the size of drawer
                point   NW, NE, SW, SE	# the 4 corners of the drawer
                line    N, S, W, E	# the 4 edges of the drawer

			# the size of the drawer is always a ratio to ...
			# ... the desk.
		width = ~/length div 3
		length = ~/width - ~/width div k
		k = 2			# initially, the draw is half open

		NW = ~/NE		# NW is always at desk's NE
		SW = NW - {0, width}	# the other 3 corners are ...
		SE = SW + {length, 0}	# ... relative to NW
		NE = NW + {length, 0}	#

	        N = [NW, NE]
		S = [SW, SE]
		W = [NW, SW]
        	E = [NE, SE]
        }
}

boolean doorHitTable, cableIsShort
doorHitTable = includes(circle(door/hinge, door/width),table/NW)
cableIsShort = dist(cable.1, cable.2) > cablelength

%scout

display scr, basicScreen;
window don1, don2;
window monDoor, monCable;
point monDoorPos, monCablePos;
string monDoorStr, monCableStr;
integer _doorHitTable, _cableIsShort, _door_open;
integer _plug, _plug1;
point p1, q1, p2, q2;
integer zoomSize;
point zoomPos;
point tblMenuRef, miscMenuRef, zoomMenuRef;
point plugButtonPos, doorButtonPos;
string plugMenu, doorMenu;
window plugButton, doorButton;
point tblMenuHeaderPos, tblUpPos, tblDownPos, tblLeftPos, tblRightPos;
string tblMenuHeader, tblUpMenu, tblDownMenu, tblLeftMenu, tblRightMenu;
window tblHeader, tblUp, tblDown, tblLeft, tblRight;
point zoomMenuHeaderPos, zoomUpPos, zoomDownPos, zoomLeftPos, zoomRightPos;
string zoomMenuHeader, zoomUpMenu, zoomDownMenu, zoomLeftMenu, zoomRightMenu;
window zoomHeader, zoomUp, zoomDown, zoomLeft, zoomRight;

p1 = {25, 100};
q1 = {225, 300};
don1 = {
	box:	[p1, q1],
	pict:	"view",
	type:	DONALD,
	border:	1
	sensitive: ON
};
zoomPos = {500, 500};
zoomSize = 500;
p2 = {275, 100};
q2 = {475, 300};
don2 = {
	box:	[p2, q2],
	pict:	"view",
	type:	DONALD,
	xmin:	zoomPos.1 - zoomSize/2,
	ymin:	zoomPos.2 - zoomSize/2,
	xmax:	zoomPos.1 + zoomSize/2,
	ymax:	zoomPos.2 + zoomSize/2,
	border:	1
	sensitive: ON
};

monDoor = {
	frame:	([monDoorPos, 1, strlen(monDoorStr)]),
	string:	monDoorStr
};
monDoorStr = if _doorHitTable then "Table obstructs door" else "" endif;
monDoorPos = {25, 50};

monCable = {
	frame:	([monCablePos, 1, strlen(monCableStr)]),
	string:	monCableStr
};
monCableStr = if _cableIsShort then "Cable is not long enough" else "" endif;
monCablePos = {25, 70};

tblMenuRef = {100, 400};
miscMenuRef = {250, 400};
zoomMenuRef = {400, 400};

plugButtonPos = miscMenuRef - {strlen(plugMenu).c / 2, 1.r};
plugButton = {
	frame:	([plugButtonPos, 1, strlen(plugMenu)]),
	string:	plugMenu,
	border:	1
	sensitive: ON
};
plugMenu = if _plug == _plug1 then "9:Use Plug 2" else "9:Use Plug 1" endif;

doorButtonPos = miscMenuRef + {-strlen(doorMenu).c / 2, 1.r};
doorButton = {
	frame:	([doorButtonPos, 1, strlen(doorMenu)]),
	string:	doorMenu,
	border:	1
	sensitive: ON
};
doorMenu = if _door_open then "10:Close Door" else "10:Open Door" endif;

tblMenuHeader = "Table Position";
tblMenuHeaderPos = tblMenuRef - {(strlen(tblMenuHeader)/2).c, 4.r};
tblHeader = {
	frame:	([tblMenuHeaderPos, 1, strlen(tblMenuHeader)]),
	string: tblMenuHeader
};

tblUpPos = tblMenuRef - {(strlen(tblUpMenu)/2).c, 2.r};
tblUp = {
	frame:	([tblUpPos, 1, strlen(tblUpMenu)]),
	string:	tblUpMenu,
	border:	1
	sensitive: ON
};
tblUpMenu = "1:Up";

tblDownPos = tblMenuRef + {-(strlen(tblDownMenu)/2).c, 2.r};
tblDown = {
	frame:	([tblDownPos, 1, strlen(tblDownMenu)]),
	string:	tblDownMenu,
	border:	1
	sensitive: ON
};
tblDownMenu = "2:Down";

tblLeftPos = tblMenuRef - {(strlen(tblLeftMenu) + 1).c, 0};
tblLeft = {
	frame:	([tblLeftPos, 1, strlen(tblLeftMenu)]),
	string:	tblLeftMenu,
	border:	1
	sensitive: ON
};
tblLeftMenu = "3:Left";

tblRightPos = tblMenuRef + {1.c, 0};
tblRight = {
	frame:	([tblRightPos, 1, strlen(tblRightMenu)]),
	string:	tblRightMenu,
	border:	1
	sensitive: ON
};
tblRightMenu = "4:Right";

zoomMenuHeader = "Zoom Position";
zoomMenuHeaderPos = zoomMenuRef - {(strlen(zoomMenuHeader)/2).c, 4.r};
zoomHeader = {
	frame:	([zoomMenuHeaderPos, 1, strlen(zoomMenuHeader)]),
	string: zoomMenuHeader
};

zoomUpPos = zoomMenuRef - {(strlen(zoomUpMenu)/2).c, 2.r};
zoomUp = {
	frame:	([zoomUpPos, 1, strlen(zoomUpMenu)]),
	string:	zoomUpMenu,
	border:	1
	sensitive: ON
};
zoomUpMenu = "5:Up";

zoomDownPos = zoomMenuRef + {-(strlen(zoomDownMenu)/2).c, 2.r};
zoomDown = {
	frame:	([zoomDownPos, 1, strlen(zoomDownMenu)]),
	string:	zoomDownMenu,
	border:	1
	sensitive: ON
};
zoomDownMenu = "6:Down";

zoomLeftPos = zoomMenuRef - {(strlen(zoomLeftMenu) + 1).c, 0};
zoomLeft = {
	frame:	([zoomLeftPos, 1, strlen(zoomLeftMenu)]),
	string:	zoomLeftMenu,
	border:	1
	sensitive: ON
};
zoomLeftMenu = "7:Left";

zoomRightPos = zoomMenuRef + {1.c, 0};
zoomRight = {
	frame:	([zoomRightPos, 1, strlen(zoomRightMenu)]),
	string:	zoomRightMenu,
	border:	1
	sensitive: ON
};
zoomRightMenu = "8:Right";

basicScreen = < tblHeader / tblUp / tblDown / tblLeft / tblRight /
	   zoomHeader / zoomUp / zoomDown / zoomLeft / zoomRight /
	   plugButton / doorButton /
	   don1 / don2 >;

scr = if _doorHitTable then
	append(basicScreen, 1, monDoor)
      else
	basicScreen
      endif;

#screen = < monDoor / monCable /
#	   tblHeader / tblUp / tblDown / tblLeft / tblRight /
#	   zoomHeader / zoomUp / zoomDown / zoomLeft / zoomRight /
#	   plugButton / doorButton /
#	   don1 / don2 >;

screen = if _cableIsShort then
		append(scr, 1, monCable)
	 else
		scr
	 endif;

%eden
proc handle_user_input : input
{
	switch (input) {
	case 1:	_table_SW = vector_add(_table_SW, cart(0, 100));	break;
	case 2:	_table_SW = vector_sub(_table_SW, cart(0, 100));	break;
	case 3:	_table_SW = vector_sub(_table_SW, cart(100, 0));	break;
	case 4:	_table_SW = vector_add(_table_SW, cart(100, 0));	break;
	case 5: zoomPos = pt_add(zoomPos, [0, 100]);			break;
	case 6: zoomPos = pt_subtract(zoomPos, [0, 100]);		break;
	case 7: zoomPos = pt_subtract(zoomPos, [100, 0]);		break;
	case 8: zoomPos = pt_add(zoomPos, [100, 0]);			break;
	case 9: if (_plug == _plug1) {
			_plug is _plug2;
		} else {
			_plug is _plug1;
		}
		break;
	case 10: _door_open = !_door_open;				break;
	}
}

proc plugButton_to_input : plugButton_mouse_1 {
	if (plugButton_mouse_1[2] == 4) input = 9;
}

proc doorButton_to_input : doorButton_mouse_1 {
	if (doorButton_mouse_1[2] == 4) input = 10;
}

proc tblUp_to_input : tblUp_mouse_1 {
	if (tblUp_mouse_1[2] == 4) input = 1;
}

proc tblDown_to_input : tblDown_mouse_1 {
	if (tblDown_mouse_1[2] == 4) input = 2;
}

proc tblLeft_to_input : tblLeft_mouse_1 {
	if (tblLeft_mouse_1[2] == 4) input = 3;
}

proc tblRight_to_input : tblRight_mouse_1 {
	if (tblRight_mouse_1[2] == 4) input = 4;
}

proc zoomUp_to_input : zoomUp_mouse_1 {
	if (zoomUp_mouse_1[2] == 4) input = 5;
}

proc zoomDown_to_input : zoomDown_mouse_1 {
	if (zoomDown_mouse_1[2] == 4) input = 6;
}

proc zoomLeft_to_input : zoomLeft_mouse_1 {
	if (zoomLeft_mouse_1[2] == 4) input = 7;
}

proc zoomRight_to_input : zoomRight_mouse_1 {
	if (zoomRight_mouse_1[2] == 4) input = 8;
}

proc don1_to_tableSW : don1_mouse {
    auto mx, my;
    mx = don1_mouse[4];
    my = don1_mouse[5];
    if (don1_mouse[2] == 4) {
	if (_table_SW[2] < mx && mx < _table_NE[2] &&
	    _table_SW[3] < my && my < _table_NE[3]) move_table = 1;
	old_table_SW = _table_SW;
	old_mouse_pos = [mx, my];
    }
    if (don1_mouse[2] == 5) {
	if (move_table == 1) {
	    _table_SW = cart(old_table_SW[2] + mx - old_mouse_pos[1],
			     old_table_SW[3] + my - old_mouse_pos[2]);
	    move_table = 0;
	}
    }
}

proc don2_to_tableSW : don2_mouse {
    auto mx, my, xmin, xmax, ymin, ymax, m, c, cpi;
    if (don2_mouse[2] == 4) {
	mx = don2_mouse[4];
	my = don2_mouse[5];
	xmin = dotint(don2, 6);
	ymin = dotint(don2, 7);
	xmax = dotint(don2, 8);
	ymax = dotint(don2, 9);
	m = (ymax - ymin) / (xmax - xmin);
	c = ymin - m * xmin;
	cpi = ymax + m * xmin;
	if ((my - m * mx) > c)
		input = ((my + m * mx) > cpi) ? 5 : 7;
	else
		input = ((my + m * mx) > cpi) ? 8 : 6;
    }
}
