From 90cd981e807be9ecdc1cc253d2b6726a15713574 Mon Sep 17 00:00:00 2001 From: Material Foundry Date: Thu, 26 Sep 2024 23:12:30 +0200 Subject: [PATCH] v3.2.1 --- MaterialPlane.js | 5 +- changelog.md | 18 + css/style.css | 270 +++ img/.thumb/MaterialFoundry2560x1440.jpg.jpg | Bin 0 -> 11232 bytes img/.thumb/macro.png.jpg | Bin 0 -> 13180 bytes lang/en.json | 2 + module.json | 7 +- src/Communication/websocket.js | 25 +- src/IRtoken/tokenHelpers.js | 4 +- src/Misc/compatibilityHandler.js | 3 - src/Misc/misc.js | 16 + src/analyzeTouch.js | 4 +- src/calibration.js | 269 +-- templates/calibrationProgressScreen.html | 14 +- templates/config.html | 1760 ++++++++----------- 15 files changed, 1226 insertions(+), 1171 deletions(-) create mode 100644 css/style.css create mode 100644 img/.thumb/MaterialFoundry2560x1440.jpg.jpg create mode 100644 img/.thumb/macro.png.jpg diff --git a/MaterialPlane.js b/MaterialPlane.js index 076c7f0..b817db3 100644 --- a/MaterialPlane.js +++ b/MaterialPlane.js @@ -215,6 +215,9 @@ Hooks.on('ready', async ()=>{ else if (payload.msgType == 'refresh') { window.location.reload(); } + else if (payload.msgType == 'calConfig') { + calibrationProgress.configureElements(payload.config, true) + } if (game.user.isGM) { if (payload.msgType == "controlToken") { lastToken = game.canvas.tokens.get(payload.tokenId); @@ -324,8 +327,6 @@ Hooks.on('closempConfig',() => { Hooks.on('closecalibrationProgressScreen',() => { removeOverlay(); calibrationProgress.setCalibrationRunning(false) - console.log('stopping calibration') - sendWS({event:"calibration", state:"cancel"}); }); diff --git a/changelog.md b/changelog.md index ced99ed..61f827f 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,23 @@ # Changelog Material Plane Foundry Module +### v3.2.1 - 26-09-2024 + +Additions: + + +Fixes: + + +Other: + + ### v3.2.0 - 16-08-2024 Additions: diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..cb9fd9d --- /dev/null +++ b/css/style.css @@ -0,0 +1,270 @@ +.mpConfigTab { + overflow: hidden; + display:flex; +} + +.mpConfigTab button { + background-color: #ccc; + float: left; + border: 1px solid black; + outline: none; + cursor: pointer; + transition: 0.3s; + border-radius: 5px 5px 0px 0px; +} + +.mpConfigTab button:hover { + background-color: #ddd; + +} + +.mpConfigTab button.active { + background-color: inherit; + border: 1px solid black; + border-bottom: none; +} + +.mpConfigTabContent { + padding: 6px 12px; + border: 1px solid black; + border-top: none; + min-height: 300px; + max-height: 700px; + overflow: auto; +} + +.mpContentSensor { + height: 500px; + max-height: 500px; + overflow: hidden; +} + +.mpConfigFormElements{ + width: 100%; + display: flex; + margin-bottom: 1px; + align-items: center; +} + +.mpConfigFormElements label { + width: 50%; +} + +.mpConfigFormElements .mpConfigFormVal, +.mpConfigFormElements .mpConfigFormValRange, +.mpConfigFormElements .mpConfigFormBtn { + position: relative; + display: flex; + justify-content: flex-end; + width: 50%; +} + +.mpConfigFormElements .mpConfigFormVal input[type='text'], +.mpConfigFormElements .mpConfigFormVal input[type='number'], +.mpConfigFormElements .mpConfigFormVal select, +.mpConfigFormElements .mpConfigFormValRange input[type='range'] { + flex-grow: 4; +} + +.mpConfigFormElements .mpConfigFormValRange input[type='number'] { + width: 25%; + margin-left: 5px; +} + +.mpConfigFormElements .mpConfigFormBtn button { + width: 100%; + margin-left: 5px; +} + +.mpConfigFormElements .mpConfigFormBtn select { + min-width: 50%; + transform: translateY(10%); +} + +.mpConfigNotes { + font-size: 0.85em; + font-style: italic; + color: grey; + margin-bottom: 5px; +} + +.mpNotes { + font-size: 0.9em; + color: black; + margin-bottom: 5px; +} + +.mpBaseTableId { + flex: 0 0 10%; +} +.mpBaseTableName { + flex: 0 0 20%; +} +.mpBaseTableLink { + text-align: center; + flex: 0 0 7%; +} +header.mpBaseTableHeader { + background: rgba(0, 0, 0, 0.5); + width: 100%; + padding: 5px; + border: 1px solid #191813; + text-align: left; + font-weight: bold; + color: #f0f0e0; + font-weight: bold; + text-shadow: 1px 1px #000; +} +.mpIrTableName { + flex: 0 0 25%; +} + +.mpIrTableProtocol{ + flex: 0 0 12.5% +} + +.mpIrTableCode{ + flex: 0 0 15%; +} + +.mpIrTableMacro{ + flex: 0 0 15%; +} + +.mpIrTableArgument{ + flex: 0 0 12.5%; +} + +.mpIrTableDelay{ + flex: 0 0 7.5%; +} + +.mpIrTableLink{ + flex: 0 0 5%; +} + +.mpConfigContent table, +.mpConfigContent th, +.mpConfigContent td { + border: 1px solid black; +} +.mpConfigContent canvas { + border: 2px solid rgb(151, 149, 149); +} +.mpExpandable { + cursor: pointer; +} +.mpCollapsed { + display:none; +} +.mpExpandableIcon { + border: none; +} + +.mpConfigColumn { + float: left; + width: 48%; + margin: 1%; +} + +.mpConfigColumnLeft { + height: 425px; + overflow: auto; +} + +.mpConfigColumn label { + width: 35%; +} + +.mpConfigColumn .mpConfigFormVal, +.mpConfigColumn .mpConfigFormValRange, +.mpConfigColumn .mpConfigFormBtn { + width: 65%; +} + +/* Clear floats after the columns */ +.mpConfigRow:after { + content: ""; + display: table; + clear: both; +} + +.mpDownloadsTable, +.mpDownloadsTable th, +.mpDownloadsTable td { + border: none; +} + +.mpDownloadsColumnLabel { + width:25%; + text-align: left; +} +.mpDownloadsColumnVersion { + width:15%; + text-align: center; +} +.mpDownloadsColumnOS { + width:15%; + text-align: center; +} +.mpDownloadsColumnButton { + width:15%; + text-align: center; +} +.mpDownloadsBtn { + width:50%; +} + +/* Tooltip container */ +.mpTooltip { + position: relative; + display: inline-block; + cursor: default; + overflow: visible; + max-width: 100%; +} + +/* Tooltip text */ +.mpTooltip .mpTooltiptext { + visibility: hidden; + background-color: black; + text-align: center; + padding: 5px; + margin-left: 5px; + border-radius: 6px; + min-width: 200px; + max-width: 200px; + opacity: 0.75; + + top: -15px; + position: absolute; + z-index: 1; + font-size: 12px; + font-style: italic; + font-weight: normal; + color: darkgrey; +} + +/* Show the tooltip text when you mouse over the tooltip container */ +.mpTooltip:hover .mpTooltiptext { + visibility: visible; +} + +.MaterialPlane_Config { + max-height: 500px; +} + +.mpBaseListContainer { + min-height: 150px; + max-height: 150px; + overflow-y: scroll; +} + +.mpCalError { + background-color: orange; + border: solid 1px black; + border-radius: 10px; + margin: 5px; + padding: 5px; + font-size: 0.9em; +} \ No newline at end of file diff --git a/img/.thumb/MaterialFoundry2560x1440.jpg.jpg b/img/.thumb/MaterialFoundry2560x1440.jpg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..87e2aaa5ce5b5c51e9a912b3b355fd2ce011880b GIT binary patch literal 11232 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 BuWA4Q literal 0 HcmV?d00001 diff --git a/img/.thumb/macro.png.jpg b/img/.thumb/macro.png.jpg new file mode 100644 index 0000000000000000000000000000000000000000..12ff4742cb7eb99788fabb526af0e85d682cf812 GIT binary patch literal 13180 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 { - document.getElementById('mpCalStartButton').style.display = 'none'; - document.getElementById('mpCalOffsetSelector').style.display = 'none'; - document.getElementById('mpCalSinglepointSelector').style.display = 'none'; - document.getElementById('mpCalLocationSelector').style.display = 'none'; - - document.getElementById('mpCalMethodExplanation').style.display = 'none'; - - document.getElementById('mpCalOffsetSel').value = ''; - document.getElementById('mpCalSinglepointSel').value = ''; - document.getElementById('mpCalLocationSel').value = ''; - - if (game.settings.get(moduleName,'ActiveUser') == game.userId) calOverlay.init(''); + configureElements(config, socket=false) { + this.config = config; + + hideElement("mpCalMethodExplanation"); + hideElement("mpCalSinglepointSelector"); + hideElement("mpCalSinglepointDescription"); + hideElement('mpCalOffsetSelector'); + hideElement('mpCalOffsetDescription'); + hideElement('mpCalStartButton'); + hideElement('mpCalLocationDescription'); + hideElement('mpCalLocationSelector'); + hideElement('mpCalOffsetDescription'); + + if (socket) { + setSelectElement("mpCalMethodSel", config.methodSel); + setSelectElement("mpCalOffsetSel", config.customMode); + setSelectElement("mpCalSinglepointSel", config.pointMode); + setSelectElement("mpCalLocationSel", config.location); + } + + if (config.methodSel === '') { + showElement("mpCalMethodExplanation"); + if (game.settings.get(moduleName,'ActiveUser') === game.userId) calOverlay.init(''); + } + else if (config.methodSel === 'Normal') { + showElement("mpCalSinglepointSelector"); + showElement("mpCalSinglepointDescription"); - if (event.target.value == '') { - document.getElementById('mpCalMethodExplanation').style.display = ''; + if (config.pointMode === '') { + showElement('mpCalSinglepointDescription'); + if (game.settings.get(moduleName,'ActiveUser') === game.userId) calOverlay.init(''); + } + else if (config.pointMode) { + hideElement('mpCalSinglepointDescription'); + showElement('mpCalLocationDescription'); + showElement('mpCalLocationSelector'); + if (game.settings.get(moduleName,'ActiveUser') === game.userId) calOverlay.init('both'); + } + + if (config.location === '') { + showElement('mpCalLocationDescription'); + } + else if (config.location) { + showElement('mpCalStartButton'); } + + if (config.pointMode != '') { + if (config.location === 'On-Screen') { + if (game.settings.get(moduleName,'ActiveUser') === game.userId) calOverlay.init('onScreen'); + } + else if (config.location === 'Corner') { + if (game.settings.get(moduleName,'ActiveUser') === game.userId) calOverlay.init('corners'); + } + } + } + else if (config.methodSel == 'Custom') { + showElement('mpCalOffsetSelector'); + showElement('mpCalOffsetDescription'); - if (event.target.value == 'Normal') { - document.getElementById('mpCalSinglepointSelector').style.display = ''; - document.getElementById('mpCalSinglepointDescription').style.display = ''; + if (config.customMode === '') { + showElement('mpCalOffsetDescription'); } - else if (event.target.value == 'Custom') { - document.getElementById('mpCalOffsetSelector').style.display = ''; - document.getElementById('mpCalOffsetDescription').style.display = ''; + else if (config.customMode === 'Custom') { + showElement('mpCalStartButton'); + hideElement('mpCalOffsetDescription'); } + else if (config.customMode === 'Calibrate') { + hideElement('mpCalOffsetDescription'); + showElement('mpCalSinglepointSelector'); + showElement('mpCalSinglepointDescription'); - this.setHeight(); + if (config.pointMode === '') { + showElement('mpCalSinglepointDescription'); + } + else if (config.pointMode) { + hideElement('mpCalSinglepointDescription'); + showElement('mpCalLocationDescription'); + showElement('mpCalLocationSelector'); + if (game.settings.get(moduleName,'ActiveUser') === game.userId) calOverlay.init('both'); + } + + if (config.location === '') { + showElement('mpCalLocationDescription'); + } + else if (config.location) { + showElement('mpCalStartButton'); + } + + if (config.pointMode != '') { + if (config.location === 'On-Screen') { + if (game.settings.get(moduleName,'ActiveUser') === game.userId) calOverlay.init('onScreen'); + } + else if (config.location === 'Corner') { + if (game.settings.get(moduleName,'ActiveUser') === game.userId) calOverlay.init('corners'); + } + } + } + } + + this.setHeight(); + + if (!socket) game.socket.emit(`module.MaterialPlane`, { + msgType: "calConfig", + config }); + } - html.find("select[id='mpCalOffsetSel']").on("change", event => { - document.getElementById('mpCalLocationSel').value = ''; - document.getElementById('mpCalLocationSelector').style.display = 'none'; - document.getElementById('mpCalStartButton').style.display = 'none'; - document.getElementById('mpCalSinglepointSelector').style.display = 'none'; + - document.getElementById('mpCalOffsetDescription').style.display = 'none'; - if (game.settings.get(moduleName,'ActiveUser') == game.userId) calOverlay.init(''); + activateListeners(html) { + super.activateListeners(html); - if (event.target.value == '') { - document.getElementById('mpCalOffsetDescription').style.display = ''; - } + html.find("select[id='mpCalMethodSel']").on("change", event => { + if (game.settings.get(moduleName,'ActiveUser') == game.userId) calOverlay.init(''); + this.config.methodSel = event.target.value; + this.configureElements(this.config); + }); - if (event.target.value == 'Custom') { - document.getElementById('mpCalStartButton').style.display = ''; - document.getElementById('mpCalSinglepointSelector').style.display = ''; - document.getElementById('mpCalSinglepointDescription').style.display = ''; - } - else if (event.target.value == 'Calibrate') { - document.getElementById('mpCalStartButton').style.display = ''; - } + html.find("select[id='mpCalOffsetSel']").on("change", event => { + if (game.settings.get(moduleName,'ActiveUser') == game.userId) calOverlay.init(''); + this.config.customMode = event.target.value; + this.configureElements(this.config); }); html.find("select[id='mpCalLocationSel']").on("change", event => { - document.getElementById('mpCalLocationDescription').style.display = 'none'; - document.getElementById('mpCalStartButton').style.display = 'none'; if (game.settings.get(moduleName,'ActiveUser') == game.userId) calOverlay.init('both'); - - if (event.target.value == '') { - document.getElementById('mpCalLocationDescription').style.display = ''; - } - else { - document.getElementById('mpCalStartButton').style.display = ''; - } - - if (event.target.value == 'On-Screen') { - if (game.settings.get(moduleName,'ActiveUser') == game.userId) calOverlay.init('onScreen'); - } - else if (event.target.value == 'Corner') { - if (game.settings.get(moduleName,'ActiveUser') == game.userId) calOverlay.init('corners'); - } + this.config.location = event.target.value; + this.configureElements(this.config); + }); html.find("select[id='mpCalSinglepointSel']").on("change", event => { - document.getElementById('mpCalLocationDescription').style.display = 'none'; - document.getElementById('mpCalLocationSelector').style.display = 'none'; - document.getElementById('mpCalLocationSel').value = ''; - - const calMode = document.getElementById('mpCalMethodSel').value; - - if (calMode == 'Normal') { - if (event.target.value == '') { - document.getElementById('mpCalSinglepointDescription').style.display = ''; - } - else { - document.getElementById('mpCalSinglepointDescription').style.display = 'none'; - document.getElementById('mpCalLocationDescription').style.display = ''; - document.getElementById('mpCalLocationSelector').style.display = ''; - if (game.settings.get(moduleName,'ActiveUser') == game.userId) calOverlay.init('both'); - } - } - else { - if (event.target.value == '') { - document.getElementById('mpCalSinglepointDescription').style.display = ''; - } - else { - document.getElementById('mpCalSinglepointDescription').style.display = 'none'; - } - } + this.config.pointMode = event.target.value; + this.configureElements(this.config); }); html.find("button[name='mpStartCalibration']").on("click", event => { @@ -177,9 +213,9 @@ export class calibrationProgressScreen extends FormApplication { mode } - if (mode != 'Offset' && locationSel == 'On-Screen') { + if (locationSel == 'On-Screen') msg.calibrationBounds = calibrationBounds; - } + sendWS(msg); }); @@ -200,6 +236,7 @@ export class calibrationProgressScreen extends FormApplication { init() { if (game.settings.get(moduleName,'ActiveUser') != game.userId && !game.user.isGM) return; + this.config = {}; this.calibrationMode = 'init'; this.calibrationRunning = true; this.render(true); @@ -389,6 +426,7 @@ export class calibrationProgressScreen extends FormApplication { export function removeOverlay(){ if (game.settings.get(moduleName,'ActiveUser') != game.userId) return; if (calOverlay == undefined) return; + window.removeEventListener("mouseout", calOverlay.mouseOutEventHandler); canvas.stage.removeChild(calOverlay); calOverlay.remove(); calOverlay = undefined; @@ -480,44 +518,36 @@ export class calibrationOverlay extends ControlsLayer { $('#players').hide(); $('#hotbar').hide(); - var interval; - let oldScreenLeft = window.screenLeft; - let oldScreenTop = window.screenTop; - this.activeScreenXOffset = 0; - this.activeScreenYOffset = 0; - let counter = 0; - let parent = this; - window.addEventListener("mouseout", function(evt){ - if (evt.toElement === null && evt.relatedTarget === null) { - interval = setInterval(function () { - if (counter > 40 || oldScreenLeft != window.screenLeft || oldScreenTop != window.screenTop) { - counter = 0; - oldScreenLeft = window.screenLeft; - oldScreenTop = window.screenTop; - - parent.update(); - } - counter++; - }, 25); - } else { - clearInterval(interval); - } + window.addEventListener("resize", (evt) => { + if (!calOverlay) return; + calOverlay.update() }); } - + update() { - const activeScreenX = Math.floor((window.screenLeft+window.outerWidth/2)/screen.width); - const activeScreenY = Math.floor((window.screenTop+window.outerHeight/2)/screen.height); - this.activeScreenXOffset = (window.screenLeft - (activeScreenX + 0.5)*screen.width + window.outerWidth/2)/canvas.scene._viewPosition.scale; - this.activeScreenYOffset = (window.screenTop - (activeScreenY + 0.5)*screen.height + window.outerHeight/2)/canvas.scene._viewPosition.scale; + if (document.getElementById("mpCalError")) { + //Check if window is fullscreen + const isNotFullScreen = screen.width != window.innerWidth || screen.height != window.innerHeight; + + //Check for browser zoom or display scaling + const isScaled = window.devicePixelRatio != 1; + + if (isNotFullScreen || isScaled) + document.getElementById("mpCalError").style.display = ""; + else + document.getElementById("mpCalError").style.display = "none"; + + document.getElementById("MaterialPlane_CalProgMenu").style.height = "auto" + } + //Calculate the amount of pixels that are visible on the screen const horVisible = screen.width/canvas.scene._viewPosition.scale; const vertVisible = screen.height/canvas.scene._viewPosition.scale; - const x = canvas.scene._viewPosition.x - this.activeScreenXOffset; - let y = canvas.scene._viewPosition.y - this.activeScreenYOffset; - + const x = canvas.scene._viewPosition.x; + let y = canvas.scene._viewPosition.y; + if (this.mode == 'onScreen' || this.mode == 'both') { const xOffset = 2*horVisible/5; const yOffset = 2*vertVisible/6; @@ -595,6 +625,7 @@ export class calibrationOverlay extends ControlsLayer { * Remove the marker */ remove() { + window.removeEventListener("resize", calOverlay.update()) this.container.removeChildren(); $('#MaterialPlane_CalMenu').show(); $('#logo').show(); diff --git a/templates/calibrationProgressScreen.html b/templates/calibrationProgressScreen.html index 5ee097a..c3140d5 100644 --- a/templates/calibrationProgressScreen.html +++ b/templates/calibrationProgressScreen.html @@ -44,7 +44,7 @@

Calibration Configuration

  1. Calibrate using your chosen custom calibration points by selecting 'Custom Points'.
  2. -
  3. Calibrate to pre-defined calibration points so the sensor knows where these points are related relative to your display, by selecting 'Calibrate Custom Points'
  4. +
  5. Calibrate to pre-defined calibration points (display corner or on-screen points) so the sensor knows where these points are related relative to your display, by selecting 'Calibrate Custom Points'
After that, you only need to perform step 1, unless a different display is used, or the relative location of the sensor to the display is changed significantly. @@ -73,7 +73,7 @@

Calibration Configuration

-