not have all the same old functionality, but it uses menuitems now. This will allow us to much-better utilize the textwindows.
		
			
				
	
	
		
			409 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			409 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| //This file pertains to the textwindow.
 | |
| //We use this for displaying a puzzle's starting instructions
 | |
| //and for choosing new puzzles.
 | |
| 
 | |
| var tmOutsideYMargin=20; //How far from the top and bottom left blank
 | |
| var tmOutsideXMargin=20; //How far from right and left side left blank
 | |
| var tmBorderWidth=4;
 | |
| var tmMenuBarHight=20;
 | |
| var tmScrollBarWidth=20;
 | |
| var tmWindowBackground="grey";
 | |
| var tmTextHeight; //Calculated when we build the page
 | |
| var tmLastHighlightedIndex=-1;
 | |
| var tmTextYGap=5; //The gap between lines
 | |
| var tmPuzzleSelectMenuLevel=0;
 | |
| 
 | |
| var cachedTextMenuCanvas = null;
 | |
| 
 | |
| 
 | |
| //Print the textmenu
 | |
| function textMenuPrint(TextToPrint, selectedindex = -1, highlightedindex = -1)
 | |
| {
 | |
| 	//It would be nice to print it on top of whatever is currently there.
 | |
| 	//But we will do that later.
 | |
| 	PrintScreen(0); //Print the network, then we can lay over it
 | |
| 
 | |
| 	if(cachedTextMenuCanvas == null)
 | |
| 	{		
 | |
| 		cachedTextMenuCanvas = document.createElement('canvas');
 | |
| 		cachedTextMenuCanvas.width = MainCanvas.width - (tmOutsideXMargin * 2);
 | |
| 		cachedTextMenuCanvas.height = MainCanvas.height - (tmOutsideYMargin * 2);
 | |
| 	}
 | |
| 	//If we get here, it is already created.  Get the context
 | |
| 	var cTMCctx = cachedTextMenuCanvas.getContext('2d');
 | |
| 	var rect;
 | |
| 
 | |
| 	//Fill in the background
 | |
| 	cTMCctx.fillStyle = tmWindowBackground;
 | |
| 	cTMCctx.fillRect(0,0, cachedTextMenuCanvas.width, cachedTextMenuCanvas.height);
 | |
| 
 | |
| 	//Put the X there so we can click on it
 | |
| 	rect = makeRectangle(cachedTextMenuCanvas.width - tmScrollBarWidth, 0, tmScrollBarWidth, tmMenuBarHight, tmOutsideXMargin, tmOutsideYMargin);
 | |
| 	cTMCctx.drawImage(imageFromName("x"), rect.sx, rect.sy, rect.deltax, rect.deltay);
 | |
| 	registerActionStruct("square", rect, null, textwindow_XClick);
 | |
| 
 | |
| 
 | |
| 	//Put the DownArrow there so we can click on it
 | |
| 	cTMCctx.drawImage(imageFromName("ArrowUp"),cachedTextMenuCanvas.width - tmScrollBarWidth,tmMenuBarHight,tmScrollBarWidth,tmMenuBarHight);
 | |
| 
 | |
| 	//Put the X there so we can click on it
 | |
| 	cTMCctx.drawImage(imageFromName("ArrowDown"),cachedTextMenuCanvas.width - tmScrollBarWidth,cachedTextMenuCanvas.height - tmMenuBarHight,tmScrollBarWidth,tmMenuBarHight);
 | |
| 
 | |
| 	//Create and Draw the menu bar
 | |
| 	cTMCctx.beginPath();
 | |
| 	cTMCctx.moveTo(cachedTextMenuCanvas.width - tmScrollBarWidth,0);
 | |
| 	cTMCctx.lineTo(cachedTextMenuCanvas.width - tmScrollBarWidth,cachedTextMenuCanvas.height);
 | |
| 	cTMCctx.strokeStyle="white";
 | |
| 	cTMCctx.stroke();
 | |
| 	
 | |
| 	//horizontal line under the X
 | |
| 	cTMCctx.beginPath();
 | |
| 	cTMCctx.moveTo(cachedTextMenuCanvas.width - tmScrollBarWidth,tmMenuBarHight);
 | |
| 	cTMCctx.lineTo(cachedTextMenuCanvas.width,tmMenuBarHight);
 | |
| 	cTMCctx.strokeStyle="white";
 | |
| 	cTMCctx.stroke();
 | |
| 	
 | |
| 	var cachedTextMenuTextCanvas = document.createElement('canvas');
 | |
| 	//Figure out how much space we need. - start with a simple canvas (non expandable)
 | |
| 	
 | |
| 	cachedTextMenuTextCanvas.width = cachedTextMenuCanvas.width - tmScrollBarWidth;
 | |
| 	cachedTextMenuTextCanvas.height = cachedTextMenuCanvas.height;
 | |
| 
 | |
| 	var cTMTCctx = cachedTextMenuTextCanvas.getContext('2d');
 | |
| 	
 | |
| 	cTMTCctx.strokeStyle="black";
 | |
| 	cTMTCctx.font = "20px serif";
 | |
| 
 | |
| 	var lines = [];
 | |
| 	if(typeof(TextToPrint) === "string") 
 | |
| 		lines = fragmentTextIntoLines(cTMTCctx, TextToPrint, cachedTextMenuTextCanvas.width - 10);
 | |
| 	else
 | |
| 		lines = TextToPrint; //If we passed in a list of strings
 | |
| 	//Now we have the number of lines.
 | |
| 	var metrics = cTMTCctx.measureText("test");
 | |
| 	var yHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent + tmTextYGap; //the hight of the default font and gap
 | |
| 	tmTextHeight = yHeight; //store it for use in highlighting
 | |
| 	//console.log("Height = "+yHeight);
 | |
| 
 | |
| 	var totalHeight = (lines.length * yHeight) + tmTextYGap;
 | |
| 	
 | |
| 	if(cachedTextMenuTextCanvas.height < totalHeight) cachedTextMenuTextCanvas.height = totalHeight;// resize if needed
 | |
| 
 | |
| 	//Highlight text
 | |
| 	if (highlightedindex >= 0)
 | |
| 	{
 | |
| 		//console.log("Showing hilighted index " +  highlightedindex);
 | |
| 		//Fill in the area highlighted
 | |
| 		cTMTCctx.fillStyle = "white";
 | |
| 		cTMTCctx.globalAlpha = 0.3; //mostly transparent
 | |
| 		cTMTCctx.fillRect(0,highlightedindex * yHeight + (yHeight/3), cachedTextMenuCanvas.width, yHeight);
 | |
| 		cTMTCctx.globalAlpha = 1.0; //reset
 | |
| 	}
 | |
| 	
 | |
| 	//Chosen text
 | |
| 	if (selectedindex >= 0)
 | |
| 	{
 | |
| 		//console.log("Showing selected index " +  selectedindex + " " + yHeight);
 | |
| 		//Fill in the area highlighted
 | |
| 		cTMTCctx.fillStyle = "green";
 | |
| 		cTMTCctx.globalAlpha = 0.4; //mostly transparent
 | |
| 		cTMTCctx.fillRect(0,selectedindex * yHeight + (yHeight/3), cachedTextMenuCanvas.width, yHeight);
 | |
| 		cTMTCctx.globalAlpha = 1.0; //reset
 | |
| 	}
 | |
| 	
 | |
| 	cTMTCctx.fillStyle = "black";
 | |
| 	cTMTCctx.strokeStyle="black";
 | |
| 
 | |
| 	
 | |
| 	//Now, print text on the canvas.
 | |
| 	for (var i = 0; i < lines.length; i++)
 | |
| 	{
 | |
| 		cTMTCctx.fillText(lines[i], 5, ((i+1) * yHeight));
 | |
| 		//console.log("printing text part: " + lines[i]);
 | |
| 	}
 | |
| 	
 | |
| 	//Write the text canvas on the main canvas.  If we are scrolled up or down, do that.
 | |
| 	cTMCctx.drawImage(cachedTextMenuTextCanvas,0,0);
 | |
| 	
 | |
| 	//create and Draw the scroll-bar on the side
 | |
| 	//Then make the text if we have not done so
 | |
| 	//Finally print on top of the main canvas
 | |
| 	MainCanvas_ctx.globalAlpha = 0.9; //some transparancy
 | |
| 	MainCanvas_ctx.drawImage(cachedTextMenuCanvas,tmOutsideXMargin, tmOutsideYMargin)
 | |
| 	MainCanvas_ctx.globalAlpha = 1; //reset transparancy
 | |
| }
 | |
| 
 | |
| 
 | |
| function fragmentTextIntoLines(ctx, text, maxWidth) {
 | |
| 	var words = text.split(" ");
 | |
| 	var lines = [];
 | |
| 	var currentLine = words[0];
 | |
| 
 | |
| 	for (var i = 1; i < words.length; i++) {
 | |
| 		var word = words[i];
 | |
| 		var width = ctx.measureText(currentLine + " " + word).width;
 | |
| 		if (width < maxWidth) {
 | |
| 			currentLine += " " + word;
 | |
| 		} else {
 | |
| 			lines.push(currentLine);
 | |
| 			currentLine = word;
 | |
| 		}
 | |
| 	}
 | |
| 	lines.push(currentLine);
 | |
| 	return lines;
 | |
| }
 | |
| 
 | |
| function TextWindow_handleMouseUp(evt)
 | |
| {
 | |
| 	console.log("TextWindow Mouse Up");
 | |
| 	//If we get here, it is a mouse-click event.  See if we are on the X
 | |
| 	if(mouseDownLocation.pageX + tmScrollBarWidth >= cachedTextMenuCanvas.width - tmScrollBarWidth)
 | |
| 	{
 | |
| 			console.log("TextWindow Mouse Up - X fits");
 | |
| 
 | |
| 		//The X fits.  Now, see which button, or scroll-bar we clicked on.
 | |
| 		if(mouseDownLocation.pageY - tmOutsideYMargin <= tmMenuBarHight 
 | |
| 			&& mouseDownLocation.pageY - tmOutsideYMargin >= 0)
 | |
| 		{
 | |
| 			console.log("TextWindow Mouse Up - Y fits");
 | |
| 
 | |
| 			//We clicked the X
 | |
| 			
 | |
| 			textwindow_XClick();
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		if(uiMode == 2)
 | |
| 		{
 | |
| 			//We are in puzzle-select mode and clicked somewhere.
 | |
| 			var levellist=networkNamesMatchingText("Level"+tmPuzzleSelectMenuLevel);
 | |
| 			if(tmLastHighlightedIndex>=0 && tmLastHighlightedIndex< levellist.length)
 | |
| 			{
 | |
| 				//We found a puzzle
 | |
| 				console.log("Clicked on puzzle: " + levellist[tmLastHighlightedIndex]);
 | |
| 				uiMode=1;
 | |
| 				switchPuzzle(levellist[tmLastHighlightedIndex]);
 | |
| 
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	mouseDidMovement=false; //reset it after we raise the button
 | |
| }
 | |
| 
 | |
| function textwindow_XClick(point, object) {
 | |
| 	//When the x is clicked, we do not care about the position or object.  There is no object
 | |
| 	//Dispose of the text window
 | |
| 	uiMode = 0;
 | |
| 
 | |
| 	//dispose of temp canvas; will recreate later if needed			
 | |
| 	cachedTextMenuCanvas = null;
 | |
| 	cachedTextMenuTextCanvas = null;
 | |
| 
 | |
| 	//Redraw the screen
 | |
| 	PrintScreen();
 | |
| }
 | |
| 
 | |
| function PrintPuzzleSelectMenu(level=0)
 | |
| {
 | |
| 	var levellist=networkNamesMatchingText("Level"+level);
 | |
| 	//console.log("list is this long: " + levellist.length);
 | |
| 	//textMenuPrint(levellist, -1, tmLastHighlightedIndex);
 | |
| 	//tmPuzzleSelectMenuLevel=level;
 | |
| 
 | |
| 	//
 | |
| 	var local_menuitems = [];
 | |
| 	for (var i = 1; i < levellist.length; i++) {
 | |
| 		var item = new menuitem(null, levellist[i], levellist[i], null, null, textMenu_PuzzleClick)
 | |
| 		local_menuitems.push(item);
 | |
| 	}
 | |
| 	var local_menu = new menuclass(null);
 | |
| 	local_menu.items = local_menuitems;
 | |
| 	menuPrint(local_menu);
 | |
| }
 | |
| 
 | |
| function textMenu_PuzzleClick(text, name, source, dest) {
 | |
| 	//If we get here, someone clicked on a puzzle name.  Select it and move on
 | |
| 	//We are in puzzle-select mode and clicked somewhere.
 | |
| 	//if (text == null) { } //!== does not work properly
 | |
| 	//else {
 | |
| 	//	console.log("Clicked on puzzle: " + text);
 | |
| 	//	uiMode = 1;
 | |
| 	//	switchPuzzle(text);
 | |
| 	//}
 | |
| }
 | |
| function textMenu_HandleMouseMove(evt)
 | |
| {
 | |
| 	//var highlighted_index = Math.floor(((evt.pageY - tmOutsideYMargin) - (tmTextHeight/3)) / tmTextHeight);
 | |
| 	//if(tmLastHighlightedIndex != highlighted_index) 
 | |
| 	//{
 | |
| 	//	//the index has changed
 | |
| 	//	console.log("index = " + highlighted_index);
 | |
| 	//	tmLastHighlightedIndex = highlighted_index;
 | |
| 	//	PrintPuzzleSelectMenu(tmPuzzleSelectMenuLevel);
 | |
| 	//}
 | |
| }
 | |
| 
 | |
| 
 | |
| class menuitem {
 | |
| 	constructor(rectangle, shownText, payloadName = null, payloadSource = null, payloadDest = null, clickFunc=null) {
 | |
| 		this.rectangle = rectangle
 | |
| 		this.shownText = shownText
 | |
| 		this.payloadName = payloadName //The command, such as 'delete', 'power-on', 'ping', etc
 | |
| 		this.payloadSource = payloadSource //The link, device, or original item.
 | |
| 		this.payloadDest = payloadDest //The destination device, etc.  Often null unless we are pinging or tracert
 | |
| 		this.clickFunc = clickFunc
 | |
| 	}
 | |
| }
 | |
| 
 | |
| //Our menuclass will have a menu.  We need to be able to have cascading menus (one on top of the other)
 | |
| //so we can return to a past menu if we have moved on to a child menu.
 | |
| class menuclass {
 | |
| 	constructor(sourceItem) {
 | |
| 		this.SourceItem = sourceItem
 | |
| 		this.hmargin = 10 //horizontal margin on both left and right
 | |
| 		this.vmargin = 10 //virtical margin on both top and bottom
 | |
| 		this.backcolor = "grey" //The background color
 | |
| 		this.font = "20px serif" //font and size
 | |
| 		this.textcolor = "black" //Font color
 | |
| 		this.items = [] //An array of menuitems
 | |
| 		this.TextYGap = 3; //The gap to add to the size
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| function menuPrint(menu, menutop = 0, highlightedindex = -1) {
 | |
| 	//the menu is the menuclass that holds everything
 | |
| 	//menutop is the top=most item.  If we scroll up and down, this changes.
 | |
| 	//highlighted index is the item that has been moused-over.  When this changes, re-draw the menu
 | |
| 
 | |
| 	PrintScreen(0); //Print the network, then we can lay over it
 | |
| 
 | |
| 	//This menu covers the entire place.
 | |
| 	cachedTextMenuCanvas = document.createElement('canvas');
 | |
| 	cachedTextMenuCanvas.width = MainCanvas.width - (tmOutsideXMargin * 2);
 | |
| 	cachedTextMenuCanvas.height = MainCanvas.height - (tmOutsideYMargin * 2);
 | |
| 
 | |
| 	//Get the context
 | |
| 	var cTMCctx = cachedTextMenuCanvas.getContext('2d');
 | |
| 	var tw_rect;
 | |
| 
 | |
| 	var tw_width=0;      //the width of the menu alltogether
 | |
| 	var tw_height=0;     //the height of the menu alltogether
 | |
| 	var tw_itemHeight=0; //the height of both the font and margin spacing
 | |
| 	var tw_rect;         //the rectangle we end up using
 | |
| 	//We need to figure out the size of the menu.
 | |
| 	//Do we have an item to print?  If so, add that at top
 | |
| 	if (menu.SourceItem == null) {
 | |
| 		//!== null does not work right
 | |
| 	}
 | |
| 	else {
 | |
| 		tw_height = imageSize + 10;
 | |
| 	}
 | |
| 	var tw_startY = tw_height;
 | |
| 	//Calculate the size of each text line
 | |
| 	//Add spacing.  If we are larger than the alloted space, add arrows at top and bottom
 | |
| 	//Then we can fill in the area based on all of this.
 | |
| 
 | |
| 	cTMCctx.strokeStyle = menu.textcolor;
 | |
| 	cTMCctx.font = menu.font;
 | |
| 
 | |
| 	var metrics = cTMCctx.measureText("test");
 | |
| 	var yHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent + menu.TextYGap; //the hight of the default font and gap
 | |
| 	var tw_TextHeight = yHeight; //store it for use
 | |
| 
 | |
| 	var maxWidth = 0;
 | |
| 	//determine max width (width of longest text line)
 | |
| 	for (var index = 0; index < menu.items.length; index++) {
 | |
| 		var tmetrics = cTMCctx.measureText(menu.items[index].shownText);
 | |
| 		var xWidth = tmetrics.width;
 | |
| 		if (xWidth > maxWidth) maxWidth = xWidth; 
 | |
| 	}
 | |
| 
 | |
| 	maxWidth = maxWidth + 20 + menu.hmargin;
 | |
| 
 | |
| 	if (maxWidth > cachedTextMenuCanvas.width) maxWidth = cachedTextMenuCanvas.width;
 | |
| 
 | |
| 	tw_width = maxWidth;
 | |
| 	//determine height (if we have more items than fit, figure out what will fit)
 | |
| 
 | |
| 	tw_height += menu.items.length * yHeight;
 | |
| 	if(tw_height > cachedTextMenuCanvas.height) tw_height = cachedTextMenuCanvas.height;
 | |
| 
 | |
| 	//Now that we have the width and height, center it
 | |
|     var x = (cachedTextMenuCanvas.width - tw_width) / 2;
 | |
|     var y = (cachedTextMenuCanvas.height - tw_height) / 2;
 | |
| 
 | |
| 	//make a rectangle of the correct size
 | |
| 	//Use that rectangle to place the closing X at the top
 | |
| 
 | |
| 	tw_rect = makeRectangle(x, y, tw_width, tw_height);
 | |
| 
 | |
| 	//fill in the whole thing with white and opaque
 | |
| 	drawshape("square", makeRectangle(0, 0, cachedTextMenuCanvas.width, cachedTextMenuCanvas.height), "white", .5, cTMCctx);
 | |
| 
 | |
| 
 | |
| 	//Fill in the background, nearly fully but showing a very little behind
 | |
| 	drawshape("square", tw_rect, menu.backcolor, .9, cTMCctx);
 | |
| 
 | |
| 
 | |
| 	//Put the X there so we can click on it
 | |
| 	rect = makeRectangle(cachedTextMenuCanvas.width - tmScrollBarWidth, y, tmScrollBarWidth, tmMenuBarHight, tmOutsideXMargin, tmOutsideYMargin);
 | |
| 	cTMCctx.drawImage(imageFromName("x"), rect.sx, rect.sy, rect.deltax, rect.deltay);
 | |
| 	registerActionStruct("square", rect, null, textwindow_XClick);
 | |
| 
 | |
| 
 | |
| 	//Put the UpArrow there so we can click on it
 | |
| 	cTMCctx.drawImage(imageFromName("ArrowUp"), cachedTextMenuCanvas.width - tmScrollBarWidth, tmMenuBarHight, tmScrollBarWidth, tmMenuBarHight);
 | |
| 
 | |
| 	//Put the DownArrow there so we can click on it
 | |
| 	cTMCctx.drawImage(imageFromName("ArrowDown"), cachedTextMenuCanvas.width - tmScrollBarWidth, cachedTextMenuCanvas.height - tmMenuBarHight, tmScrollBarWidth, tmMenuBarHight);
 | |
| 
 | |
| 	//Create and Draw the menu bar
 | |
| 	cTMCctx.beginPath();
 | |
| 	cTMCctx.moveTo(cachedTextMenuCanvas.width - tmScrollBarWidth, 0);
 | |
| 	cTMCctx.lineTo(cachedTextMenuCanvas.width - tmScrollBarWidth, cachedTextMenuCanvas.height);
 | |
| 	cTMCctx.strokeStyle = "white";
 | |
| 	cTMCctx.stroke();
 | |
| 
 | |
| 	//horizontal line under the X
 | |
| 	cTMCctx.beginPath();
 | |
| 	cTMCctx.moveTo(cachedTextMenuCanvas.width - tmScrollBarWidth, tmMenuBarHight);
 | |
| 	cTMCctx.lineTo(cachedTextMenuCanvas.width, tmMenuBarHight);
 | |
| 	cTMCctx.strokeStyle = "white";
 | |
| 	cTMCctx.stroke();
 | |
| 	
 | |
| 	var oldfill = cTMCctx.fillStyle;
 | |
| 	var oldstroke = cTMCctx.strokeStyle;
 | |
| 
 | |
| 	cTMCctx.font = menu.font;
 | |
| 	cTMCctx.fillStyle = menu.textcolor;
 | |
| 	cTMCctx.strokeStyle = menu.textcolor;
 | |
| 
 | |
| 	for (var index = menutop; index < menu.items.length; index++) {
 | |
| 		var ty = tw_startY + (tw_TextHeight * (index - menutop));
 | |
| 		//x is already defined
 | |
| 		cTMCctx.fillText(menu.items[index].shownText, x, ty);
 | |
| 		metrics = cTMCctx.measureText(menu.items[index].shownText);
 | |
| 		var trect = makeRectangle(x + 20, ty, metrics.width, tw_TextHeight);
 | |
| 		menu.items[index].rectangle = trect;
 | |
| 
 | |
| 		registerActionStruct("square", trect, menu.items[index], puzzle_clickOn, null, generic_mouseoverHighlight);
 | |
| 	}
 | |
| 
 | |
| 	cTMCctx.fillStyle = oldfill;
 | |
| 	cTMCctx.strokeStyle = oldstroke;
 | |
| 
 | |
| 
 | |
| 
 | |
| 	MainCanvas_ctx.globalAlpha = 0.9; //some transparancy
 | |
| 	MainCanvas_ctx.drawImage(cachedTextMenuCanvas, tmOutsideXMargin, tmOutsideYMargin)
 | |
| 	MainCanvas_ctx.globalAlpha = 1; //reset transparancy
 | |
| 
 | |
| }
 | |
| 
 | |
| function puzzle_clickOn(point, actionrec) {
 | |
| 	console.log("clicking on puzzle:" + actionrec.theObject.shownText);
 | |
| 	uiMode = 1;
 | |
| 	switchPuzzle(actionrec.theObject.shownText);
 | |
| } |