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);
|
|
} |