mirror of
https://github.com/hawkeye-stan/msfs-popout-panel-manager.git
synced 2024-11-21 13:20:11 +00:00
Squashed commit of the following:
commit 2bbda3c4e4969fdf05566908fde01f1c9e4e23f7 Author: Stanley <hawkeyesk@outlook.com> Date: Mon Sep 5 23:54:39 2022 -0400 Added in-game panel support commit ec29b0ec2612b10e45ab9a73c10b88a98fcf6eaf Author: Stanley <hawkeyesk@outlook.com> Date: Sun Sep 4 21:21:37 2022 -0400 Added in-game panel support commit 97edc184f349e1fde74a15a643fb90fb9bd90395 Author: Stanley <hawkeyesk@outlook.com> Date: Thu Sep 1 18:08:44 2022 -0400 Update touch panel commit da48ca0a272290466952c5c1bd1ca035d56f930c Author: Stanley <hawkeyesk@outlook.com> Date: Mon Aug 29 22:19:38 2022 -0400 Added pop out panel temporary display commit 701346193804f93616b0e6e2222d9d55223f516f Author: Stanley <hawkeyesk@outlook.com> Date: Wed Aug 24 10:33:59 2022 -0400 Added auto resize window display mode commit 98cbcd949f1555b44db22267ce5c54858bef47cd Author: Stanley <hawkeyesk@outlook.com> Date: Wed Aug 24 09:39:38 2022 -0400 Added auto resize window display mode
This commit is contained in:
parent
9555185274
commit
43caff1ca9
52 changed files with 633 additions and 885 deletions
3
Addons/InGameToolbar/.gitignore
vendored
3
Addons/InGameToolbar/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
|||
_Temp/
|
||||
Packages/
|
||||
PackagesMetadata/
|
Binary file not shown.
|
@ -1,30 +0,0 @@
|
|||
<AssetPackage Name="pop-out-manager" Version="1.0.0">
|
||||
<ItemSettings>
|
||||
<ContentType>SPB</ContentType>
|
||||
<Title>pop-out-manager</Title>
|
||||
<Manufacturer>Stanley Kwok</Manufacturer>
|
||||
<Creator>Stanley Kwok</Creator>
|
||||
</ItemSettings>
|
||||
<Flags>
|
||||
<VisibleInStore>false</VisibleInStore>
|
||||
<CanBeReferenced>false</CanBeReferenced>
|
||||
</Flags>
|
||||
<AssetGroups>
|
||||
<AssetGroup Name="pop-out-manager">
|
||||
<Type>SPB</Type>
|
||||
<Flags>
|
||||
<FSXCompatibility>false</FSXCompatibility>
|
||||
</Flags>
|
||||
<AssetDir>PackageSources\pop-out-manager\</AssetDir>
|
||||
<OutputDir>InGamePanels\</OutputDir>
|
||||
</AssetGroup>
|
||||
<AssetGroup Name="html-ui">
|
||||
<Type>Copy</Type>
|
||||
<Flags>
|
||||
<FSXCompatibility>false</FSXCompatibility>
|
||||
</Flags>
|
||||
<AssetDir>PackageSources\html_ui\</AssetDir>
|
||||
<OutputDir>html_ui\</OutputDir>
|
||||
</AssetGroup>
|
||||
</AssetGroups>
|
||||
</AssetPackage>
|
Binary file not shown.
|
@ -1,138 +0,0 @@
|
|||
body.modal-open {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
body.modal-open .stepDialog {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
pop-out-manager #popOutManager .ingameUiWrapper .horizontalLayout {
|
||||
background-color: var(--backgroundColorPanel);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1em 1em;
|
||||
}
|
||||
|
||||
pop-out-manager #popOutManager .ingameUiWrapper .horizontalLayout #profileInfo {
|
||||
flex: 1 1 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
pop-out-manager #popOutManager .ingameUiWrapper .horizontalLayout #panelConfigTable {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: solid 1px white;
|
||||
flex: 20 1 0;
|
||||
}
|
||||
|
||||
pop-out-manager #popOutManager .ingameUiWrapper .horizontalLayout #panelConfigButtons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
position: relative;
|
||||
margin: 2em 1em 1em 1em;
|
||||
flex: 2 1 0;
|
||||
}
|
||||
|
||||
pop-out-manager #popOutManager .ingameUiWrapper .panelConfigButton {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 6em;
|
||||
height: 3em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
pop-out-manager #popOutManager .ingameUiWrapper .lockPanelsButton {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 10em;
|
||||
height: 3em;
|
||||
}
|
||||
|
||||
.panelRow {
|
||||
display: flex;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.panelRow .column1 {
|
||||
width: 34%;
|
||||
}
|
||||
|
||||
.panelRow .column2 {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
.panelRow .column3 {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
.panelRow .column4 {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
.panelRow .column5 {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
.panelRow .column6 {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
.panelRow .column7 {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
.panelRow .column8 {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
.panelRow .column9 {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
.panelCell {
|
||||
display: flex;
|
||||
padding: 0.7em 1em;
|
||||
margin: 0;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
border-bottom: solid 1px white;
|
||||
border-right: solid 1px white;
|
||||
}
|
||||
|
||||
.panelCell:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.panelCell .alignCenter {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.panelCell ui-input .default-input input {
|
||||
padding-left: 0.25em;
|
||||
padding-right: 0.25em;
|
||||
}
|
||||
|
||||
.panelCell checkbox-element .checkbox .choices .iconWrapper .icon {
|
||||
width: 1.6em;
|
||||
height: 1.6em;
|
||||
}
|
||||
|
||||
|
||||
.stepDialog {
|
||||
display: none; /* Hidden by default */
|
||||
position: fixed; /* Stay in place */
|
||||
z-index: 1; /* Sit on top */
|
||||
left: 20vw;
|
||||
top: 20vh;
|
||||
width: 60vw; /* Full width */
|
||||
height: 60vh; /* Full height */
|
||||
overflow: auto; /* Enable scroll if needed */
|
||||
background-color: rgba(161, 153, 153, 1);
|
||||
}
|
||||
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="/SCSS/common.css" />
|
||||
<link rel="stylesheet" href="PopOutManager.css" />
|
||||
|
||||
<script type="text/javascript" src="/JS/coherent.js"></script>
|
||||
<script type="text/javascript" src="/JS/common.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/JS/buttons.js"></script>
|
||||
<script type="text/javascript" src="/JS/Services/ToolBarPanels.js"></script>
|
||||
<script type="text/javascript" src="/JS/Services/Notifications.js"></script>
|
||||
|
||||
<link rel="import" href="/templates/virtualScroll/virtualScroll.html" />
|
||||
<link rel="import" href="/templates/NewPushButton/NewPushButton.html" />
|
||||
<link rel="import" href="/templates/DropDown/DropDown.html" />
|
||||
<link rel="import" href="/templates/tabMenu/tabMenu.html" />
|
||||
<link rel="import" href="/templates/ingameUi/ingameUi.html" />
|
||||
<link rel="import" href="/templates/ingameUiHeader/ingameUiHeader.html" />
|
||||
<link rel="import" href="/templates/checkbox/checkbox.html" />
|
||||
<link rel="import" href="/templates/uiInput/uiInput.html" />
|
||||
|
||||
|
||||
<script type="text/javascript" src="PopOutManager.js"></script>
|
||||
</head>
|
||||
|
||||
<body class="border-box">
|
||||
<pop-out-manager>
|
||||
<ingame-ui id="popOutManager" panel-id="PANEL_POP_OUT_MANAGER" title=""
|
||||
class="ingameUiFrame panelInvisible condensedPanel" resize="both" min-width="160" min-height="90"
|
||||
content-fit="true" auto-inside>
|
||||
|
||||
|
||||
<div id="panelSelection" class="horizontalLayout" style="display:block">
|
||||
<div id="profileInfo">Panel Locations and Settings - <span id="planeProfileName"></span></div>
|
||||
<div id="panelSelection">
|
||||
Panel Selection
|
||||
<drop-down id="dropdownProfile" style="width:50vw"></drop-down>
|
||||
<icon-button id="addProfile" data-url="/icons/open.svg"></icon-button>
|
||||
<icon-button id="deleteProfile" data-url="/icons/reduce.svg"></icon-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="panelConfiguration" class="horizontalLayout" style="display:none">
|
||||
<div id="profileInfo">Panel Locations and Settings - <span id="planeProfileName"></span></div>
|
||||
<virtual-scroll id="panelConfigTable" direction="y">
|
||||
</virtual-scroll>
|
||||
<div id="panelConfigButtons">
|
||||
<new-push-button id="btnMinusTen" title="-10 px" class="panelConfigButton"></new-push-button>
|
||||
<new-push-button id="btnMinusOne" title="-1 px" class="panelConfigButton"></new-push-button>
|
||||
<new-push-button id="btnPlusOne" title="+1 px" class="panelConfigButton"></new-push-button>
|
||||
<new-push-button id="btnPlusTen" title="+10 px" class="panelConfigButton" toolTip="test"></new-push-button>
|
||||
<div>
|
||||
<new-push-button id="btnLockPanels" title="Lock Panels" class="lockPanelsButton"></new-push-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ingame-ui>
|
||||
</pop-out-manager>
|
||||
|
||||
|
||||
<div id="dialogBegin" class="stepDialog">
|
||||
<new-push-button id="btnStartPopOut" parentStep="stepBegin" title="Start Pop Out" class="stepButton"></new-push-button>
|
||||
<new-push-button id="btnCreateNewProfile" parentStep="stepBegin" title="Create New Profile" class="stepButton"></new-push-button>
|
||||
<new-push-button id="btnAdjustProfile" parentStep="stepBegin" title="Adjust Profile" class="stepButton"></new-push-button>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,388 +0,0 @@
|
|||
class PopOutManagerPanelElement extends UIElement {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.ingameUi = null;
|
||||
this.isInitialized = false;
|
||||
this.panelActive = false;
|
||||
this.webSocket = null;
|
||||
this.webSocketConnected = false;
|
||||
this.webSocketInterval = null;
|
||||
|
||||
this.tryConnectWebSocket = () => {
|
||||
this.lockPanel(true);
|
||||
|
||||
this.webSocket = new WebSocket("ws://localhost:27011/ws");
|
||||
|
||||
this.webSocket.onopen = () => {
|
||||
clearInterval(this.webSocketInterval);
|
||||
this.webSocketConnected = true;
|
||||
};
|
||||
|
||||
this.webSocket.onclose = () => {
|
||||
this.webSocketConnected = false;
|
||||
|
||||
// Clear panel table
|
||||
this.createPanelConfigTableHeader(this.panelConfigTable);
|
||||
this.lockPanel(true);
|
||||
|
||||
this.webSocketInterval = setInterval(() => {
|
||||
if (!this.webSocketConnected)
|
||||
this.tryConnectWebSocket();
|
||||
}, 2000)
|
||||
};
|
||||
|
||||
this.webSocket.onerror = () => {
|
||||
this.webSocket.close();
|
||||
};
|
||||
|
||||
this.webSocket.onmessage = (event) => {
|
||||
if (event.data !== undefined) {
|
||||
|
||||
var panelData = JSON.parse(event.data);
|
||||
|
||||
// only recreate panel rows if panel is refreshed (minimize/maximize, pop out)
|
||||
if (this.panelActive && document.getElementsByClassName("panelRow").length == 1)
|
||||
this.createPanelConfigTableBody(this.panelConfigTable, panelData);
|
||||
|
||||
if (panelData !== undefined && panelData !== null && panelData.length !== 0) {
|
||||
this.lockPanel(false);
|
||||
this.bindPanelData(panelData);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
this.webSocketInterval = setInterval(() => {
|
||||
if (!this.webSocketConnected)
|
||||
this.tryConnectWebSocket();
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
this.ingameUi = this.querySelector('ingame-ui');
|
||||
this.panelSelection = document.getElementById("panelSelection");
|
||||
this.panelConfiguration = document.getElementById("panelConfiguration");
|
||||
this.planeProfileName = document.getElementById("planeProfileName");
|
||||
this.panelConfigTable = document.getElementById("panelConfigTable");
|
||||
this.btnLockPanels = this.querySelector('#btnLockPanels');
|
||||
this.btnPlusTen = this.querySelector('#btnPlusTen');
|
||||
this.btnPlusOne = this.querySelector('#btnPlusOne');
|
||||
this.btnMinusTen = this.querySelector('#btnMinusTen');
|
||||
this.btnMinusOne = this.querySelector('#btnMinusOne');
|
||||
|
||||
this.dropdownProfile = this.querySelector("#dropdownProfile");
|
||||
this.addProfile = document.getElementById("addProfile");
|
||||
this.deleteProfile = document.getElementById("deleteProfile");
|
||||
|
||||
this.stepBeginDialog = document.getElementById("stepBeginDialog");
|
||||
|
||||
|
||||
this.closeDialog = document.getElementById("closeDialog");
|
||||
|
||||
//this.deleteProfile.disable(!this.deleteProfile.disabled);
|
||||
|
||||
//this.dropdownProfile.addEventListener("select", (event) = {});
|
||||
|
||||
let workflow = new Workflow(this);
|
||||
workflow.bindAllButtonEvents();
|
||||
workflow.stepBegin();
|
||||
|
||||
|
||||
this.addProfile.addEventListener("click", (event) => {
|
||||
addProfileDialog.style.display = "block";
|
||||
//this.ingameUi.toggleExternPanel(true);
|
||||
document.body.classList.toggle('modal-open');
|
||||
|
||||
// let value = new DataValue;
|
||||
// value.name = "New Profile " + dropDownValues.length;
|
||||
// value.ID = dropDownValues.length;
|
||||
// dropDownValues.push(value);
|
||||
// this.dropdownProfile.setData(dropDownValues, dropDownValues.length - 1);
|
||||
});
|
||||
|
||||
this.deleteProfile.addEventListener("click", (event) => {
|
||||
// dropDownValues.splice(-1,1);
|
||||
// this.dropdownProfile.setData(dropDownValues, dropDownValues.length - 1);
|
||||
});
|
||||
|
||||
|
||||
this.isLocked = false;
|
||||
|
||||
let profiles = ["Kodiak", "172", "737"];
|
||||
let dropDownValues = [];
|
||||
profiles.forEach((profile, index) => {
|
||||
let value = new DataValue;
|
||||
value.name = profile;
|
||||
value.ID = index;
|
||||
dropDownValues.push(value);
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
this.dropdownProfile.setData(dropDownValues, 2)
|
||||
|
||||
|
||||
}, 1000);
|
||||
|
||||
|
||||
|
||||
this.btnLockPanels.addEventListener("click", () => {
|
||||
if (this.btnLockPanels.disabled)
|
||||
return;
|
||||
|
||||
this.isLocked = !this.isLocked;
|
||||
|
||||
this.lockPanel(this.isLocked);
|
||||
|
||||
if (this.isLocked) {
|
||||
this.btnLockPanels.disabled = false;
|
||||
this.btnLockPanels.title = "Unlock Panels";
|
||||
this.btnLockPanels.style.backgroundColor = "red";
|
||||
}
|
||||
else {
|
||||
this.btnLockPanels.disabled = false;
|
||||
this.btnLockPanels.title = "Lock Panels";
|
||||
this.btnLockPanels.style.backgroundColor = null;
|
||||
}
|
||||
|
||||
this.panelSelection.style.display = 'block';
|
||||
this.panelConfiguration.style.display = 'none';
|
||||
});
|
||||
|
||||
|
||||
if (this.ingameUi) {
|
||||
this.ingameUi.addEventListener("panelActive", (e) => {
|
||||
//document.getElementsByClassName("Extern")[0].style.display = "none"; // disable extern button
|
||||
this.createPanelConfigTableHeader(this.panelConfigTable);
|
||||
|
||||
this.panelActive = true;
|
||||
this.lockPanel(true);
|
||||
|
||||
if (this.webSocketConnected)
|
||||
this.webSocket.send("RequestPanelData");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
createPanelConfigTableHeader(panelConfigTable) {
|
||||
let panelRow;
|
||||
|
||||
// remove all child of panelConfigTable
|
||||
while (panelConfigTable.firstChild) {
|
||||
panelConfigTable.removeChild(panelConfigTable.firstChild);
|
||||
}
|
||||
|
||||
// create header
|
||||
panelRow = this.createPanelRow(true);
|
||||
panelRow.appendChild(this.createPanelCell("div", "column1", "Panel Name"));
|
||||
panelRow.appendChild(this.createPanelCell("div", "column2", "X-Pos"));
|
||||
panelRow.appendChild(this.createPanelCell("div", "column3", "Y-Pos"));
|
||||
panelRow.appendChild(this.createPanelCell("div", "column4", "Width"));
|
||||
panelRow.appendChild(this.createPanelCell("div", "column5", "Height"));
|
||||
panelRow.appendChild(this.createPanelCell("div", "column6", "Always on Top"));
|
||||
panelRow.appendChild(this.createPanelCell("div", "column7", "Hide Title Bar"));
|
||||
panelRow.appendChild(this.createPanelCell("div", "column8", "Full Screen Mode"));
|
||||
panelRow.appendChild(this.createPanelCell("div", "column9", "Touch Enabled"));
|
||||
panelConfigTable.appendChild(panelRow);
|
||||
}
|
||||
|
||||
createPanelConfigTableBody(panelConfigTable, panelData) {
|
||||
let panelRow;
|
||||
|
||||
if (panelConfigTable !== undefined) {
|
||||
for (let index = 0; index < panelData.length; index++) {
|
||||
panelRow = this.createPanelRow(false);
|
||||
panelRow.appendChild(this.createPanelCell("div", "column1", this.createUiInput("PanelName_" + index)));
|
||||
panelRow.appendChild(this.createPanelCell("div", "column2", this.createUiInput("XPos_" + index)));
|
||||
panelRow.appendChild(this.createPanelCell("div", "column3", this.createUiInput("YPos_" + index)));
|
||||
panelRow.appendChild(this.createPanelCell("div", "column4", this.createUiInput("Width_" + index)));
|
||||
panelRow.appendChild(this.createPanelCell("div", "column5", this.createUiInput("Height_" + index)));
|
||||
panelRow.appendChild(this.createPanelCell("div", "column6", this.createCheckbox("AlwaysOnTop_" + index)));
|
||||
panelRow.appendChild(this.createPanelCell("div", "column7", this.createCheckbox("HideTitleBar_" + index)));
|
||||
panelRow.appendChild(this.createPanelCell("div", "column8", this.createCheckbox("FullScreenMode_" + index)));
|
||||
panelRow.appendChild(this.createPanelCell("div", "column9", this.createCheckbox("TouchEnabled_" + index)));
|
||||
panelConfigTable.appendChild(panelRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createPanelRow(isHeaderRow) {
|
||||
let panelRow = document.createElement("div");
|
||||
|
||||
if (isHeaderRow)
|
||||
panelRow.classList.add("panelHeaderRow");
|
||||
|
||||
panelRow.classList.add("panelRow");
|
||||
|
||||
return panelRow;
|
||||
}
|
||||
|
||||
createPanelCell(cellType, classes = null, childElement) {
|
||||
let cell = document.createElement(cellType);
|
||||
cell.classList.add("panelCell");
|
||||
|
||||
if (classes !== undefined || classes !== null) {
|
||||
if (typeof (classes) === "string") {
|
||||
cell.classList.add(classes);
|
||||
}
|
||||
else {
|
||||
for (let index = 0; index < classes.length; index++)
|
||||
cell.classList.add(classes[index]);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof (childElement) === "string")
|
||||
cell.innerHTML = `<div class='alignCenter'>${childElement}</div>`;
|
||||
else
|
||||
cell.appendChild(childElement);
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
createUiInput(id) {
|
||||
let input = document.createElement("ui-input");
|
||||
input.type = "text";
|
||||
input.id = id;
|
||||
return input;
|
||||
}
|
||||
|
||||
createCheckbox(id) {
|
||||
let checkbox = document.createElement("checkbox-element");
|
||||
checkbox.id = id;
|
||||
checkbox.style.width = "1em";
|
||||
return checkbox;
|
||||
}
|
||||
|
||||
lockPanel(isLocked) {
|
||||
if (this.panelActive) {
|
||||
let uiInputs = document.getElementsByTagName("ui-input");
|
||||
for (let index = 0; index < uiInputs.length; index++) {
|
||||
uiInputs[index].disabled = isLocked;
|
||||
}
|
||||
|
||||
let checkboxes = document.getElementsByTagName("checkbox-element");
|
||||
for (let index = 0; index < checkboxes.length; index++) {
|
||||
checkboxes[index].SetData({ sTitle: "", bToggled: checkboxes.toggled, bDisabled: isLocked });
|
||||
checkboxes[index].RefreshValue();
|
||||
}
|
||||
|
||||
this.btnLockPanels.disabled = isLocked;
|
||||
if(isLocked)
|
||||
{
|
||||
this.btnLockPanels.title = "Lock Panels";
|
||||
this.btnLockPanels.style.backgroundColor = null;
|
||||
}
|
||||
|
||||
this.btnPlusTen.disabled = isLocked;
|
||||
this.btnPlusOne.disabled = isLocked;
|
||||
this.btnMinusTen.disabled = isLocked;
|
||||
this.btnMinusOne.disabled = isLocked;
|
||||
}
|
||||
}
|
||||
|
||||
bindPanelData(panelData) {
|
||||
if (this.panelActive) {
|
||||
panelData.forEach((panel, index) => {
|
||||
this.bindUiInput("PanelName_" + index, panel.panelName, "text");
|
||||
this.bindUiInput("XPos_" + index, panel.xPos);
|
||||
this.bindUiInput("YPos_" + index, panel.yPos);
|
||||
this.bindUiInput("Width_" + index, panel.width);
|
||||
this.bindUiInput("Height_" + index, panel.height);
|
||||
this.bindCheckbox("AlwaysOnTop_" + index, panel.alwaysOnTop);
|
||||
this.bindCheckbox("HideTitleBar_" + index, panel.hideTitleBar);
|
||||
this.bindCheckbox("FullScreenMode_" + index, panel.fullScreenMode);
|
||||
this.bindCheckbox("TouchEnabled_" + index, panel.touchEnabled);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
bindUiInput(id, value, type) {
|
||||
let input = document.getElementById(id);
|
||||
input.style.width = "100%";
|
||||
input.setValue(value);
|
||||
|
||||
if (type === "text")
|
||||
input.children[0].children[0].style.textAlign = "left";
|
||||
}
|
||||
|
||||
bindCheckbox(id, value) {
|
||||
let checkbox = document.getElementById(id);
|
||||
checkbox.SetData({ sTitle: "", bToggled: value, bDisabled: false });
|
||||
checkbox.RefreshValue();
|
||||
}
|
||||
}
|
||||
window.customElements.define("pop-out-manager", PopOutManagerPanelElement);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Workflow {
|
||||
constructor(owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
get workflowSteps() {
|
||||
return [
|
||||
{
|
||||
name: 'stepBegin',
|
||||
results:
|
||||
[
|
||||
{ value: 'stepCreateNewProfile' },
|
||||
{ value: 'stepStartPopOut' },
|
||||
{ value: 'stepAdjustProfile' }
|
||||
]
|
||||
}]
|
||||
}
|
||||
|
||||
getFuncName() {
|
||||
return this.getFuncName.caller.name;
|
||||
}
|
||||
|
||||
bindAllButtonEvents(){
|
||||
let stepButtons = document.getElementsByClassName("stepButton");
|
||||
Array.from(stepButtons).forEach(btn => {
|
||||
btn.addEventListener("click", (e) => {
|
||||
let parentStep = e.target.getAttribute("parentStep");
|
||||
let resultValue = e.target.id.replace("btn", "step");
|
||||
this.handleButtonClick(parentStep, resultValue);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
handleButtonClick(currentStep, resultValue) {
|
||||
let step = this.workflowSteps.find(c => c.name == currentStep);
|
||||
let result = step.results.find(f => f.value == resultValue);
|
||||
|
||||
if(result != null)
|
||||
{
|
||||
let func = this[result.value];
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
openDialog(step)
|
||||
{
|
||||
this.owner.stepBeginDialog = document.getElementById(step.replace("step", "dialog"));
|
||||
this.owner.stepBeginDialog.style.display = "block";
|
||||
document.body.classList.toggle("modal-open");
|
||||
}
|
||||
|
||||
stepBegin() {
|
||||
this.openDialog("stepBegin");
|
||||
}
|
||||
|
||||
stepStartPopOut() {
|
||||
var a = ""
|
||||
}
|
||||
|
||||
stepCreateNewProfile() {
|
||||
var a = ""
|
||||
}
|
||||
|
||||
stepAdjustProfile() {
|
||||
var a = ""
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="64.000000pt" height="64.000000pt" viewBox="0 0 64.000000 64.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<g transform="translate(0.000000,64.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M160 315 l0 -165 160 0 160 0 0 50 c0 43 -3 50 -20 50 -16 0 -20 -7
|
||||
-20 -30 l0 -30 -120 0 -120 0 0 125 0 125 30 0 c23 0 30 4 30 20 0 17 -7 20
|
||||
-50 20 l-50 0 0 -165z"/>
|
||||
<path d="M358 447 l32 -33 -50 -49 c-47 -46 -49 -50 -33 -67 16 -18 19 -17 68
|
||||
32 l51 50 27 -27 27 -28 0 78 0 77 -77 0 -77 0 32 -33z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 740 B |
|
@ -1,29 +0,0 @@
|
|||
{
|
||||
"content": [
|
||||
{
|
||||
"path": "html_ui/icons/toolbar/POP_OUT_MANAGER.svg",
|
||||
"size": 740,
|
||||
"date": 133013771715368552
|
||||
},
|
||||
{
|
||||
"path": "html_ui/InGamePanels/PopOutManagerPanel/PopOutManager.css",
|
||||
"size": 1921,
|
||||
"date": 133015501657300878
|
||||
},
|
||||
{
|
||||
"path": "html_ui/InGamePanels/PopOutManagerPanel/PopOutManager.html",
|
||||
"size": 3194,
|
||||
"date": 133023923647110813
|
||||
},
|
||||
{
|
||||
"path": "html_ui/InGamePanels/PopOutManagerPanel/PopOutManager.js",
|
||||
"size": 10854,
|
||||
"date": 133023924937932717
|
||||
},
|
||||
{
|
||||
"path": "InGamePanels/pop-out-manager.spb",
|
||||
"size": 684,
|
||||
"date": 133023927549810418
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"dependencies": [],
|
||||
"content_type": "UNKNOWN",
|
||||
"title": "pop-out-manager",
|
||||
"manufacturer": "Stanley Kwok",
|
||||
"creator": "Stanley Kwok",
|
||||
"package_version": "1.0.0",
|
||||
"minimum_game_version": "1.27.9",
|
||||
"release_notes": {
|
||||
"neutral": {
|
||||
"LastUpdate": "",
|
||||
"OlderHistory": ""
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<SimBase.Document Type="InGamePanels" version="1,0">
|
||||
<Filename>InGamePanel_PopOutManager.spb</Filename>
|
||||
<InGamePanels.InGamePanelDefinition id="PANEL_POP_OUT_MANAGER" Name="Pop Out Manager" url="html_UI/ingamePanels/PopOutManagerPanel/PopOutManager.html" resizeDirections="Both" minWidth="80" minHeight="40" defaultWidth="120" defaultHeight="50" defaultTop="30" defaultLeft="5" icon="POP_OUT_MANAGER" buttonVisible="true">
|
||||
</InGamePanels.InGamePanelDefinition>
|
||||
</SimBase.Document>
|
|
@ -1 +0,0 @@
|
|||
FOR %%i IN (*.xml) DO "%MSFS_SDK%\Tools\bin\fspackagetool.exe" %%i
|
Binary file not shown.
Before Width: | Height: | Size: 2.2 KiB |
|
@ -1,7 +0,0 @@
|
|||
<Project Version="2" Name="pop-out-manager" FolderName="Packages">
|
||||
<OutputDirectory>.</OutputDirectory>
|
||||
<TemporaryOutputDirectory>_Temp</TemporaryOutputDirectory>
|
||||
<Packages>
|
||||
<Package>PackageDefinitions\pop-out-manager.xml</Package>
|
||||
</Packages>
|
||||
</Project>
|
|
@ -10,9 +10,9 @@
|
|||
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
|
||||
<RootNamespace>MSFSPopoutPanelManager.ArduinoAgent</RootNamespace>
|
||||
<Platforms>x64</Platforms>
|
||||
<Version>3.4.2.0</Version>
|
||||
<AssemblyVersion>3.4.2.0</AssemblyVersion>
|
||||
<FileVersion>3.4.2.0</FileVersion>
|
||||
<Version>3.4.3.0</Version>
|
||||
<AssemblyVersion>3.4.3.0</AssemblyVersion>
|
||||
<FileVersion>3.4.3.0</FileVersion>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<DebugType>Embedded</DebugType>
|
||||
<Configurations>Debug;Release;DebugTouchPanel;ReleaseTouchPanel</Configurations>
|
||||
|
|
|
@ -9,8 +9,12 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
{
|
||||
public class MainOrchestrator : ObservableObject
|
||||
{
|
||||
private IntPtr _msfsGameWindowHandle;
|
||||
|
||||
public MainOrchestrator()
|
||||
{
|
||||
_msfsGameWindowHandle = IntPtr.Zero;
|
||||
|
||||
Profile = new ProfileOrchestrator();
|
||||
PanelSource = new PanelSourceOrchestrator();
|
||||
PanelPopOut = new PanelPopOutOrchestrator();
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
|
||||
<RootNamespace>MSFSPopoutPanelManager.Orchestration</RootNamespace>
|
||||
<Platforms>x64</Platforms>
|
||||
<Version>3.4.2.0</Version>
|
||||
<AssemblyVersion>3.4.2.0</AssemblyVersion>
|
||||
<FileVersion>3.4.2.0</FileVersion>
|
||||
<Version>3.4.3.0</Version>
|
||||
<AssemblyVersion>3.4.3.0</AssemblyVersion>
|
||||
<FileVersion>3.4.3.0</FileVersion>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<DebugType>Embedded</DebugType>
|
||||
<Configurations>Debug;Release;DebugTouchPanel;ReleaseTouchPanel</Configurations>
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
{
|
||||
// This will be replaced by a signal from Ready to Fly Skipper into webserver in version 4.0
|
||||
private const int READY_TO_FLY_BUTTON_APPEARANCE_DELAY = 2000;
|
||||
private int _builtInPanelConfigDelay;
|
||||
|
||||
internal ProfileData ProfileData { get; set; }
|
||||
|
||||
|
@ -35,6 +36,7 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
public event EventHandler OnPopOutStarted;
|
||||
public event EventHandler<bool> OnPopOutCompleted;
|
||||
public event EventHandler<TouchPanelOpenEventArg> OnTouchPanelOpened;
|
||||
public event EventHandler<PanelSourceCoordinate> OnPanelSourceOverlayFlashed;
|
||||
|
||||
public void ManualPopOut()
|
||||
{
|
||||
|
@ -43,9 +45,10 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
|
||||
InputHookManager.EndHook();
|
||||
|
||||
if (ActiveProfile.PanelSourceCoordinates.Count > 0 || ActiveProfile.TouchPanelBindings.Count > 0)
|
||||
if (ActiveProfile.PanelSourceCoordinates.Count > 0 || ActiveProfile.TouchPanelBindings.Count > 0 || ActiveProfile.IncludeInGamePanels)
|
||||
{
|
||||
StatusMessageWriter.WriteMessage($"Panels pop out in progress for profile:\n{ActiveProfile.ProfileName}", StatusMessageType.Info, true);
|
||||
_builtInPanelConfigDelay = 0;
|
||||
CorePopOutSteps();
|
||||
}
|
||||
}
|
||||
|
@ -67,19 +70,24 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
// Match the delay for Ready to Fly button to disappear
|
||||
Thread.Sleep(READY_TO_FLY_BUTTON_APPEARANCE_DELAY);
|
||||
|
||||
if (ActiveProfile.PanelSourceCoordinates.Count > 0 || ActiveProfile.TouchPanelBindings.Count > 0)
|
||||
if (ActiveProfile.PanelSourceCoordinates.Count > 0 || ActiveProfile.TouchPanelBindings.Count > 0 || ActiveProfile.IncludeInGamePanels)
|
||||
{
|
||||
StatusMessageWriter.WriteMessage($"Automatic pop out is starting for profile:\n{profile.ProfileName}", StatusMessageType.Info, true);
|
||||
|
||||
// Extra wait for cockpit view to appear and align
|
||||
Thread.Sleep(2000);
|
||||
|
||||
_builtInPanelConfigDelay = 4000;
|
||||
CorePopOutSteps();
|
||||
}
|
||||
}
|
||||
|
||||
private void CorePopOutSteps()
|
||||
{
|
||||
// Set Windowed Display Mode window's configuration if needed
|
||||
if (AppSettingData.AppSetting.AutoResizeMsfsGameWindow)
|
||||
WindowActionManager.SetMsfsGameWindowLocation(ActiveProfile.MsfsGameWindowConfig);
|
||||
|
||||
// Has custom pop out panels
|
||||
if (ActiveProfile.PanelSourceCoordinates.Count > 0)
|
||||
{
|
||||
|
@ -141,7 +149,7 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
return;
|
||||
}
|
||||
|
||||
if (ActiveProfile.PanelSourceCoordinates.Count == 0 && ActiveProfile.TouchPanelBindings.Count == 0)
|
||||
if (ActiveProfile.PanelSourceCoordinates.Count == 0 && ActiveProfile.TouchPanelBindings.Count == 0 && !ActiveProfile.IncludeInGamePanels)
|
||||
{
|
||||
StatusMessageWriter.WriteMessage("No panel has been selected for the profile. Please select at least one panel to continue.", StatusMessageType.Error, false);
|
||||
return;
|
||||
|
@ -179,14 +187,24 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
// Add the MSFS Touch Panel (My other github project) windows to the panel list
|
||||
if (AppSetting.TouchPanelSettings.EnableTouchPanelIntegration)
|
||||
{
|
||||
var panelResults = AddMsfsTouchPanels(panelConfigs.Count + 1);
|
||||
var panelResults = AddMsfsTouchPanels(panelConfigs.Count + 100); // add a panelIndex gap
|
||||
if (panelResults != null)
|
||||
panelConfigs.AddRange(panelResults);
|
||||
}
|
||||
|
||||
// Add the built-in panels from toolbar menu (ie. VFR Map, Check List, Weather, etc)
|
||||
if (ActiveProfile.IncludeInGamePanels)
|
||||
{
|
||||
// Allow delay to wait for in game built-in pop outs to appear
|
||||
Thread.Sleep(_builtInPanelConfigDelay);
|
||||
|
||||
var panelResults = AddBuiltInPanels(panelConfigs.Count + 200); // add a panelIndex gap
|
||||
if (panelResults != null)
|
||||
panelConfigs.AddRange(panelResults);
|
||||
}
|
||||
|
||||
if (panelConfigs.Count == 0)
|
||||
{
|
||||
OnPopOutCompleted?.Invoke(this, false);
|
||||
StatusMessageWriter.WriteMessage("No panels have been found. Please select at least one in-game panel.", StatusMessageType.Error, false);
|
||||
return;
|
||||
}
|
||||
|
@ -217,6 +235,13 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
StatusMessageWriter.WriteMessage("Panels have been popped out succesfully.", StatusMessageType.Info, true);
|
||||
OnPopOutCompleted?.Invoke(this, true);
|
||||
}
|
||||
|
||||
if (!ActiveProfile.IsLocked)
|
||||
ProfileData.WriteProfiles();
|
||||
|
||||
// For migrating existing profile, if using windows mode, save MSFS game window configuration
|
||||
if (AppSettingData.AppSetting.AutoResizeMsfsGameWindow && !ActiveProfile.MsfsGameWindowConfig.IsValid)
|
||||
ProfileData.SaveMsfsGameWindowConfig();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,18 +254,25 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
{
|
||||
var x = ActiveProfile.PanelSourceCoordinates[i - 1].X;
|
||||
var y = ActiveProfile.PanelSourceCoordinates[i - 1].Y;
|
||||
|
||||
// show the panel source overlay for split second
|
||||
Task task = new Task(() => OnPanelSourceOverlayFlashed?.Invoke(this, ActiveProfile.PanelSourceCoordinates[i - 1]));
|
||||
task.RunSynchronously();
|
||||
|
||||
InputEmulationManager.PopOutPanel(x, y, AppSetting.UseLeftRightControlToPopOut);
|
||||
|
||||
var handle = PInvoke.FindWindow("AceApp", String.Empty); // Get an AceApp window with empty title
|
||||
// Get an AceApp window with empty title
|
||||
var handle = PInvoke.FindWindow("AceApp", String.Empty);
|
||||
|
||||
// Need to move the window to upper left corner first. There is a possible bug in the game that panel pop out to full screen that prevents further clicking.
|
||||
if (handle != IntPtr.Zero)
|
||||
WindowActionManager.MoveWindow(handle, 0, 0, 1000, 500);
|
||||
|
||||
// The joined panel is always the first panel that got popped out
|
||||
if (i > 1)
|
||||
SeparatePanel(panels[0].PanelHandle); // The joined panel is always the first panel that got popped out
|
||||
SeparatePanel(panels[0].PanelHandle);
|
||||
|
||||
handle = PInvoke.FindWindow("AceApp", String.Empty); // Get an AceApp window with empty title
|
||||
handle = PInvoke.FindWindow("AceApp", String.Empty);
|
||||
|
||||
if (handle == IntPtr.Zero && i == 1)
|
||||
{
|
||||
|
@ -293,6 +325,35 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
InputEmulationManager.LeftClick(point.X, point.Y);
|
||||
}
|
||||
|
||||
private List<PanelConfig> AddBuiltInPanels(int panelIndex)
|
||||
{
|
||||
List<PanelConfig> builtinPanels = new List<PanelConfig>();
|
||||
|
||||
var panelHandles = WindowActionManager.GetWindowsByPanelType(new List<PanelType>() { PanelType.BuiltInPopout });
|
||||
|
||||
foreach (var panelHandle in panelHandles)
|
||||
{
|
||||
var rectangle = WindowActionManager.GetWindowRect(panelHandle);
|
||||
var clientRectangle = WindowActionManager.GetClientRect(panelHandle);
|
||||
|
||||
builtinPanels.Add(new PanelConfig()
|
||||
{
|
||||
PanelIndex = panelIndex,
|
||||
PanelHandle = panelHandle,
|
||||
PanelType = PanelType.BuiltInPopout,
|
||||
PanelName = WindowActionManager.GetWindowCaption(panelHandle),
|
||||
Top = rectangle.Top,
|
||||
Left = rectangle.Left,
|
||||
Width = clientRectangle.Width,
|
||||
Height = clientRectangle.Height
|
||||
});
|
||||
|
||||
panelIndex++;
|
||||
}
|
||||
|
||||
return builtinPanels.Count == 0 ? null : builtinPanels;
|
||||
}
|
||||
|
||||
private List<PanelConfig> AddMsfsTouchPanels(int panelIndex)
|
||||
{
|
||||
List<PanelConfig> touchPanels = new List<PanelConfig>();
|
||||
|
@ -357,7 +418,7 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
}
|
||||
}
|
||||
|
||||
return touchPanels;
|
||||
return touchPanels.Count == 0 ? null : touchPanels;
|
||||
}
|
||||
|
||||
private void LoadAndApplyPanelConfigs(List<PanelConfig> panelResults)
|
||||
|
@ -368,7 +429,18 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
if (panel.PanelHandle == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
var savedPanelConfig = ActiveProfile.PanelConfigs.FirstOrDefault(s => s.PanelIndex == panel.PanelIndex);
|
||||
PanelConfig savedPanelConfig = null;
|
||||
|
||||
if (panel.PanelType == PanelType.CustomPopout || panel.PanelType == PanelType.MSFSTouchPanel)
|
||||
savedPanelConfig = ActiveProfile.PanelConfigs.FirstOrDefault(s => s.PanelIndex == panel.PanelIndex);
|
||||
else if (panel.PanelType == PanelType.BuiltInPopout)
|
||||
savedPanelConfig = ActiveProfile.PanelConfigs.FirstOrDefault(s => s.PanelName == panel.PanelName);
|
||||
|
||||
if (savedPanelConfig == null)
|
||||
{
|
||||
panel.PanelHandle = IntPtr.Zero;
|
||||
return;
|
||||
}
|
||||
|
||||
// Assign previous saved values
|
||||
if (savedPanelConfig != null)
|
||||
|
@ -401,6 +473,14 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
// Apply window size again to overcome a bug in MSFS that when moving panel between monitors, panel automatic resize for no reason
|
||||
if (panel.PanelType == PanelType.BuiltInPopout)
|
||||
{
|
||||
Thread.Sleep(2000); // Overcome GTN750 bug
|
||||
WindowActionManager.MoveWindow(panel.PanelHandle, panel.Left, panel.Top, panel.Width, panel.Height);
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
if (!panel.FullScreen)
|
||||
{
|
||||
// Apply always on top
|
||||
|
@ -428,6 +508,10 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
Thread.Sleep(250);
|
||||
}
|
||||
});
|
||||
|
||||
// If profile is locked, remove all panels without handle
|
||||
if (ActiveProfile.IsLocked)
|
||||
panelResults.RemoveAll(p => p.PanelHandle == IntPtr.Zero);
|
||||
}
|
||||
|
||||
private void ReturnToAfterPopOutCameraView()
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
|
||||
private AppSetting AppSetting { get { return AppSettingData == null ? null : AppSettingData.AppSetting; } }
|
||||
|
||||
public event EventHandler<PanelSourceCoordinate> onOverlayShowed;
|
||||
public event EventHandler<PanelSourceCoordinate> OnOverlayShowed;
|
||||
public event EventHandler OnLastOverlayRemoved;
|
||||
public event EventHandler OnAllOverlaysRemoved;
|
||||
public event EventHandler OnSelectionStarted;
|
||||
|
@ -71,6 +71,11 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
}
|
||||
|
||||
InputEmulationManager.SaveCustomView(AppSettingData.AppSetting.AutoPanningKeyBinding);
|
||||
|
||||
// If using windows mode, save MSFS game window configuration
|
||||
if (AppSettingData.AppSetting.AutoResizeMsfsGameWindow)
|
||||
ProfileData.SaveMsfsGameWindowConfig();
|
||||
|
||||
StatusMessageWriter.WriteMessage("Auto Panning Camera has been saved succesfully.", StatusMessageType.Info, false);
|
||||
}
|
||||
|
||||
|
@ -100,7 +105,7 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
ActiveProfile.PanelSourceCoordinates.Add(newCoor);
|
||||
_panelIndex++;
|
||||
|
||||
onOverlayShowed?.Invoke(this, newCoor);
|
||||
OnOverlayShowed?.Invoke(this, newCoor);
|
||||
}
|
||||
|
||||
public void HandleOnLastPanelSelectionRemoved(object sender, Point e)
|
||||
|
@ -122,12 +127,16 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
if (ActiveProfile == null)
|
||||
return;
|
||||
|
||||
// Set Windowed Display Mode window's configuration if needed
|
||||
if (AppSettingData.AppSetting.AutoResizeMsfsGameWindow)
|
||||
WindowActionManager.SetMsfsGameWindowLocation(ActiveProfile.MsfsGameWindowConfig);
|
||||
|
||||
// remove all existing panel overlay display
|
||||
for (var i = 0; i < ActiveProfile.PanelSourceCoordinates.Count; i++)
|
||||
OnAllOverlaysRemoved?.Invoke(this, null);
|
||||
|
||||
foreach (var coor in ActiveProfile.PanelSourceCoordinates)
|
||||
onOverlayShowed?.Invoke(this, new PanelSourceCoordinate() { PanelIndex = coor.PanelIndex, X = coor.X, Y = coor.Y });
|
||||
OnOverlayShowed?.Invoke(this, new PanelSourceCoordinate() { PanelIndex = coor.PanelIndex, X = coor.X, Y = coor.Y });
|
||||
|
||||
// Turn off TrackIR if TrackIR is started
|
||||
FlightSimOrchestrator.TurnOffTrackIR();
|
||||
|
@ -141,7 +150,7 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
if (ActiveProfile == null)
|
||||
return;
|
||||
|
||||
// remove all existing panel overlay display
|
||||
// Remove all existing panel overlay display
|
||||
for (var i = 0; i < ActiveProfile.PanelSourceCoordinates.Count; i++)
|
||||
OnAllOverlaysRemoved?.Invoke(this, null);
|
||||
|
||||
|
@ -160,6 +169,10 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
|
||||
ProfileData.WriteProfiles();
|
||||
|
||||
// If using windows mode, save MSFS game window configuration
|
||||
if (AppSettingData.AppSetting.AutoResizeMsfsGameWindow)
|
||||
ProfileData.SaveMsfsGameWindowConfig();
|
||||
|
||||
InputHookManager.EndHook();
|
||||
|
||||
// Turn TrackIR back on
|
||||
|
|
|
@ -204,5 +204,18 @@ namespace MSFSPopoutPanelManager.Orchestration
|
|||
{
|
||||
MigrateLiveryToAircraftBinding(FlightSimData.CurrentMsfsLiveryTitle, FlightSimData.CurrentMsfsAircraft);
|
||||
}
|
||||
|
||||
public void SaveMsfsGameWindowConfig()
|
||||
{
|
||||
if (ActiveProfile == null)
|
||||
return;
|
||||
|
||||
var msfsGameWindowConfig = WindowsAgent.WindowActionManager.GetMsfsGameWindowLocation();
|
||||
if (msfsGameWindowConfig.IsValid)
|
||||
{
|
||||
ActiveProfile.MsfsGameWindowConfig = msfsGameWindowConfig;
|
||||
WriteProfiles();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
155
ReactClient/public/sharedworker.js
Normal file
155
ReactClient/public/sharedworker.js
Normal file
|
@ -0,0 +1,155 @@
|
|||
const SIMCONNECT_DATA_REQUEST_INTERVAL_SLOW = 5000;
|
||||
|
||||
var apiUrl = undefined;
|
||||
var networkStatus = false;
|
||||
var arduinoStatus = false;
|
||||
var simConnectSystemEvent = undefined;
|
||||
var simConnectData = undefined;
|
||||
|
||||
onconnect = (ev) => {
|
||||
const [port] = ev.ports;
|
||||
|
||||
port.onmessage = e => {
|
||||
apiUrl = e.data.apiUrl;
|
||||
updateInterval = e.data.updateInterval;
|
||||
|
||||
setInterval(() => {
|
||||
port.postMessage({
|
||||
networkStatus: networkStatus,
|
||||
arduinoStatus: arduinoStatus,
|
||||
simConnectSystemEvent: simConnectSystemEvent,
|
||||
simConnectData: simConnectData
|
||||
});
|
||||
}, updateInterval);
|
||||
|
||||
requestData(updateInterval);
|
||||
};
|
||||
};
|
||||
|
||||
requestData = async (updateInterval) => {
|
||||
try {
|
||||
let response = await fetch(`${apiUrl}/getdata`).catch(() => {
|
||||
throw('MSFS Touch Panel Server is unavailable.')
|
||||
});
|
||||
|
||||
if (response !== undefined) {
|
||||
let result = await response.json();
|
||||
|
||||
if (result === undefined)
|
||||
throw new Error('MSFS Touch Panel Server error');
|
||||
|
||||
|
||||
networkStatus = Boolean(result.msfsStatus ?? false);
|
||||
arduinoStatus = Boolean(result.arduinoStatus ?? false);
|
||||
|
||||
if (result.systemEvent !== null && result.systemEvent !== undefined)
|
||||
simConnectSystemEvent = result.systemEvent.split('-')[0];
|
||||
else
|
||||
simConnectSystemEvent = null;
|
||||
|
||||
if (!result.msfsStatus)
|
||||
throw('MSFS SimConnect is unavailable.')
|
||||
|
||||
var simData = JSON.parse(result.data ?? []);
|
||||
|
||||
if ((simData !== null && simData !== []))
|
||||
simConnectData = parseRequestData(simData);
|
||||
|
||||
setTimeout(() => requestData(updateInterval), updateInterval);
|
||||
}
|
||||
else {
|
||||
throw('Empty MSFS Touch Panel Server response.')
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error);
|
||||
networkStatus = false;
|
||||
setTimeout(() => requestData(SIMCONNECT_DATA_REQUEST_INTERVAL_SLOW), SIMCONNECT_DATA_REQUEST_INTERVAL_SLOW);
|
||||
}
|
||||
}
|
||||
|
||||
parseRequestData = (resultData) => {
|
||||
if (resultData === []) return [];
|
||||
|
||||
let newData = [];
|
||||
|
||||
// Format value as specified by the data key as needed and apply defaults
|
||||
resultData.forEach(item => {
|
||||
if (item.javaScriptFormatting !== null) {
|
||||
item.value = formattingMethod[item.javaScriptFormatting](item.value);
|
||||
}
|
||||
|
||||
if (item.value === null || item.value === undefined) {
|
||||
item.value = item.defaultValue;
|
||||
}
|
||||
|
||||
newData[item.propName] = item.value;
|
||||
})
|
||||
|
||||
return newData;
|
||||
}
|
||||
|
||||
formattingMethod = {
|
||||
toFixed0: (value) => {
|
||||
return value.toFixed(0);
|
||||
},
|
||||
toFixed1: (value) => {
|
||||
return value.toFixed(1);
|
||||
},
|
||||
toFixed2: (value) => {
|
||||
return value.toFixed(2);
|
||||
},
|
||||
toFixed3: (value) => {
|
||||
return value.toFixed(3);
|
||||
},
|
||||
toFixed4: (value) => {
|
||||
return value.toFixed(4);
|
||||
},
|
||||
padStartZero4: (value) => {
|
||||
return String(value).padStart(4, '0');
|
||||
},
|
||||
decToHex: (value) => {
|
||||
let str = value.toString(16);
|
||||
return str.substring(0, str.length - 4).padStart(4, '0');
|
||||
},
|
||||
toBlankIfNegative: (value) => {
|
||||
if (value < 0)
|
||||
return ''
|
||||
return value;
|
||||
},
|
||||
toBlankIfZeroOrNegative: (value) => {
|
||||
if (value <= 0)
|
||||
return ''
|
||||
|
||||
return value;
|
||||
},
|
||||
toBoeingFlapsValue: (value) => {
|
||||
value = value.toFixed(0)
|
||||
|
||||
switch (value) {
|
||||
case '0':
|
||||
return '0';
|
||||
case '1':
|
||||
return '1'
|
||||
case '2':
|
||||
return '2'
|
||||
case '3':
|
||||
return '5'
|
||||
case '4':
|
||||
return '10'
|
||||
case '5':
|
||||
return '15'
|
||||
case '6':
|
||||
return '25'
|
||||
case '7':
|
||||
return '30'
|
||||
case '8':
|
||||
return '40'
|
||||
default:
|
||||
return '5'
|
||||
}
|
||||
},
|
||||
toBoeingElevatorTrimValue: (value) => {
|
||||
return (value / 10).toFixed(2);
|
||||
}
|
||||
}
|
|
@ -14,20 +14,31 @@ const SimConnectDataProvider = ({ children }) => {
|
|||
|
||||
// request data from SimConnect on timer interval
|
||||
useEffect(() => {
|
||||
let requestInterval = null;
|
||||
|
||||
let localSettings = localStorage.getItem('settings');
|
||||
let updateInterval = localSettings !== null ? JSON.parse(localSettings).dataRefreshInterval : 500;
|
||||
|
||||
if (localSettings !== null)
|
||||
requestInterval = JSON.parse(localStorage.getItem('settings')).dataRefreshInterval;
|
||||
else
|
||||
requestInterval = 500;
|
||||
// Using sharedworker
|
||||
// sharedWorker = new SharedWorker('/sharedworker.js');
|
||||
// sharedWorker.port.start();
|
||||
// sharedWorker.port.postMessage({apiUrl: API_URL.url, updateInterval: updateInterval});
|
||||
// sharedWorker.port.onmessage = e => {
|
||||
// if(e.data !== null && e.data !== undefined)
|
||||
// setArduinoStatus(Boolean(e.data.arduinoStatus));
|
||||
// setNetworkStatus(Boolean(e.data.networkStatus));
|
||||
|
||||
// if (e.data.systemEvent !== undefined && e.data.systemEvent !== null)
|
||||
// setSimConnectSystemEvent(e.data.systemEvent.split('-')[0]);
|
||||
// else
|
||||
// setSimConnectSystemEvent(null);
|
||||
|
||||
// if(e.data.simConnectData !== undefined && e.data.simConnectData !== null)
|
||||
// setSimConnectData(e.data.simConnectData);
|
||||
// };
|
||||
|
||||
const requestData = async () => {
|
||||
try {
|
||||
let response = await fetch(`${API_URL.url}/getdata`).catch(() => {
|
||||
handleConnectionError('MSFS Touch Panel Server is not available.')
|
||||
return;
|
||||
throw('MSFS Touch Panel Server is not available.')
|
||||
});
|
||||
|
||||
if (response !== undefined) {
|
||||
|
@ -36,62 +47,37 @@ const SimConnectDataProvider = ({ children }) => {
|
|||
if (result === undefined)
|
||||
throw new Error('MSFS Touch Panel Server error');
|
||||
|
||||
if (result.msfsStatus !== null && result.msfsStatus !== undefined)
|
||||
setNetworkStatus(Boolean(result.msfsStatus));
|
||||
else
|
||||
setNetworkStatus(false);
|
||||
setNetworkStatus(Boolean(result.msfsStatus ?? false));
|
||||
setArduinoStatus(Boolean(result.arduinoStatus ?? false));
|
||||
|
||||
if (result.arduinoStatus !== null && result.arduinoStatus !== undefined)
|
||||
setArduinoStatus(Boolean(result.arduinoStatus));
|
||||
else
|
||||
setArduinoStatus(false);
|
||||
if (!result.msfsStatus)
|
||||
throw('MSFS SimConnect is not available.')
|
||||
|
||||
if (result.systemEvent !== null && result.systemEvent !== undefined)
|
||||
setSimConnectSystemEvent(result.systemEvent.split('-')[0]);
|
||||
else
|
||||
setSimConnectSystemEvent(null);
|
||||
|
||||
if (!result.msfsStatus)
|
||||
{
|
||||
handleConnectionError('MSFS SimConnect is not available.')
|
||||
return;
|
||||
}
|
||||
var simData = JSON.parse(result.data ?? []);
|
||||
|
||||
if (result.data !== null && result.data !== undefined) {
|
||||
var simData = JSON.parse(result.data);
|
||||
|
||||
if ((simData !== null && simData !== [])) {
|
||||
if ((simData !== null && simData !== []))
|
||||
setSimConnectData(parseRequestData(simData));
|
||||
clearInterval(requestInterval);
|
||||
let updateInterval = JSON.parse(localStorage.getItem('settings')).dataRefreshInterval;
|
||||
requestInterval = setInterval(() => requestData(), updateInterval);
|
||||
}
|
||||
|
||||
|
||||
setTimeout(() => requestData(), updateInterval);
|
||||
}
|
||||
else {
|
||||
clearInterval(requestInterval);
|
||||
let updateInterval = JSON.parse(localStorage.getItem('settings')).dataRefreshInterval;
|
||||
requestInterval = setInterval(() => requestData(), updateInterval);
|
||||
}
|
||||
throw('Empty MSFS Touch Panel Server response.')
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error);
|
||||
setNetworkStatus(false);
|
||||
handleConnectionError('MSFS Touch Panel Server is not available.')
|
||||
setTimeout(() => requestData(), SIMCONNECT_DATA_REQUEST_INTERVAL_SLOW);
|
||||
}
|
||||
}
|
||||
|
||||
const handleConnectionError = (errorMessage) => {
|
||||
console.error(errorMessage);
|
||||
clearInterval(requestInterval);
|
||||
requestInterval = setInterval(() => requestData(), SIMCONNECT_DATA_REQUEST_INTERVAL_SLOW); // slow down the request data interval until network reconnection
|
||||
}
|
||||
|
||||
requestData();
|
||||
|
||||
return () => {
|
||||
clearInterval(requestInterval);
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
|
@ -106,7 +92,8 @@ export default SimConnectDataProvider;
|
|||
// custom hook
|
||||
export const useSimConnectData = () => useContext(SimConnectDataContext);
|
||||
|
||||
export const simConnectGetPlanePanelProfilesInfo = async () => {
|
||||
export const simConnectGetPlanePanelProfilesInfo = async () =>
|
||||
{
|
||||
try {
|
||||
let response = await fetch(`${API_URL.url}/getplanepanelprofileinfo`);
|
||||
let data = await response.json();
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
|
||||
<RootNamespace>MSFSPopoutPanelManager.Shared</RootNamespace>
|
||||
<Platforms>x64</Platforms>
|
||||
<Version>3.4.2.0</Version>
|
||||
<AssemblyVersion>3.4.2.0</AssemblyVersion>
|
||||
<FileVersion>3.4.2.0</FileVersion>
|
||||
<Version>3.4.3.0</Version>
|
||||
<AssemblyVersion>3.4.3.0</AssemblyVersion>
|
||||
<FileVersion>3.4.3.0</FileVersion>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<DebugType>Embedded</DebugType>
|
||||
<Configurations>Debug;Release;DebugTouchPanel;ReleaseTouchPanel</Configurations>
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
|
||||
<RootNamespace>MSFSPopoutPanelManager.SimConnectAgent</RootNamespace>
|
||||
<Platforms>x64</Platforms>
|
||||
<Version>3.4.2.0</Version>
|
||||
<AssemblyVersion>3.4.2.0</AssemblyVersion>
|
||||
<FileVersion>3.4.2.0</FileVersion>
|
||||
<Version>3.4.3.0</Version>
|
||||
<AssemblyVersion>3.4.3.0</AssemblyVersion>
|
||||
<FileVersion>3.4.3.0</FileVersion>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<DebugType>Embedded</DebugType>
|
||||
<Configurations>Debug;Release;DebugTouchPanel;ReleaseTouchPanel</Configurations>
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
|
||||
<RootNamespace>MSFSPopoutPanelManager.TouchPanelAgent</RootNamespace>
|
||||
<Platforms>x64</Platforms>
|
||||
<Version>3.4.2.0</Version>
|
||||
<AssemblyVersion>3.4.2.0</AssemblyVersion>
|
||||
<FileVersion>3.4.2.0</FileVersion>
|
||||
<Version>3.4.3.0</Version>
|
||||
<AssemblyVersion>3.4.3.0</AssemblyVersion>
|
||||
<FileVersion>3.4.3.0</FileVersion>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<DebugType>Embedded</DebugType>
|
||||
<Configurations>Debug;Release;DebugTouchPanel;ReleaseTouchPanel</Configurations>
|
||||
|
|
|
@ -9,21 +9,20 @@ namespace MSFSPopoutPanelManager.UserDataAgent
|
|||
public AppSetting()
|
||||
{
|
||||
// Set defaults
|
||||
AutoUpdaterUrl = "https://raw.githubusercontent.com/hawkeye-stan/msfs-popout-panel-manager/master/autoupdate.xml";
|
||||
LastUsedProfileId = -1;
|
||||
MinimizeToTray = false;
|
||||
AutoUpdaterUrl = "https://raw.githubusercontent.com/hawkeye-stan/msfs-popout-panel-manager/master/autoupdate.xml";
|
||||
|
||||
AlwaysOnTop = true;
|
||||
UseAutoPanning = true;
|
||||
MinimizeAfterPopOut = false;
|
||||
AutoPanningKeyBinding = "0";
|
||||
MinimizeToTray = false;
|
||||
StartMinimized = false;
|
||||
AutoDisableTrackIR = true;
|
||||
|
||||
AutoPopOutPanels = true;
|
||||
|
||||
UseAutoPanning = true;
|
||||
AutoPanningKeyBinding = "0";
|
||||
MinimizeAfterPopOut = false;
|
||||
OnScreenMessageDuration = 1;
|
||||
UseLeftRightControlToPopOut = false;
|
||||
IsEnabledTouchPanelServer = false;
|
||||
|
||||
|
||||
AfterPopOutCameraView = new AfterPopOutCameraView();
|
||||
AfterPopOutCameraView.PropertyChanged += (source, e) =>
|
||||
{
|
||||
|
@ -31,6 +30,10 @@ namespace MSFSPopoutPanelManager.UserDataAgent
|
|||
OnPropertyChanged(arg.PropertyName, arg.OldValue, arg.NewValue);
|
||||
};
|
||||
|
||||
AutoDisableTrackIR = true;
|
||||
|
||||
AutoResizeMsfsGameWindow = true;
|
||||
|
||||
TouchScreenSettings = new TouchScreenSettings();
|
||||
TouchScreenSettings.PropertyChanged += (source, e) =>
|
||||
{
|
||||
|
@ -38,6 +41,7 @@ namespace MSFSPopoutPanelManager.UserDataAgent
|
|||
OnPropertyChanged(arg.PropertyName, arg.OldValue, arg.NewValue);
|
||||
};
|
||||
|
||||
IsEnabledTouchPanelServer = false;
|
||||
TouchPanelSettings = new TouchPanelSettings();
|
||||
TouchPanelSettings.PropertyChanged += (source, e) =>
|
||||
{
|
||||
|
@ -62,8 +66,6 @@ namespace MSFSPopoutPanelManager.UserDataAgent
|
|||
|
||||
public bool StartMinimized { get; set; }
|
||||
|
||||
public bool IncludeBuiltInPanel { get; set; }
|
||||
|
||||
public bool AutoPopOutPanels { get; set; }
|
||||
|
||||
public bool AutoDisableTrackIR { get; set; }
|
||||
|
@ -74,6 +76,8 @@ namespace MSFSPopoutPanelManager.UserDataAgent
|
|||
|
||||
public bool IsEnabledTouchPanelServer { get; set; }
|
||||
|
||||
public bool AutoResizeMsfsGameWindow { get; set; }
|
||||
|
||||
public AfterPopOutCameraView AfterPopOutCameraView { get; set; }
|
||||
|
||||
public TouchScreenSettings TouchScreenSettings { get; set; }
|
||||
|
|
|
@ -14,6 +14,10 @@ namespace MSFSPopoutPanelManager.UserDataAgent
|
|||
PanelSourceCoordinates = new ObservableCollection<PanelSourceCoordinate>();
|
||||
TouchPanelBindings = new ObservableCollection<TouchPanelBinding>();
|
||||
IsLocked = false;
|
||||
PowerOnRequiredForColdStart = false;
|
||||
IncludeInGamePanels = false;
|
||||
|
||||
MsfsGameWindowConfig = new MsfsGameWindowConfig();
|
||||
|
||||
// Legacy data
|
||||
BindingAircraftLiveries = new ObservableCollection<string>();
|
||||
|
@ -40,6 +44,10 @@ namespace MSFSPopoutPanelManager.UserDataAgent
|
|||
|
||||
public bool PowerOnRequiredForColdStart { get; set; }
|
||||
|
||||
public bool IncludeInGamePanels { get; set; }
|
||||
|
||||
public MsfsGameWindowConfig MsfsGameWindowConfig { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
|
@ -104,6 +112,9 @@ namespace MSFSPopoutPanelManager.UserDataAgent
|
|||
[JsonIgnore]
|
||||
public bool IsCustomPopOut { get { return PanelType == PanelType.CustomPopout; } }
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsBuiltInPopOut { get { return PanelType == PanelType.BuiltInPopout; } }
|
||||
|
||||
[JsonIgnore]
|
||||
public IntPtr PanelHandle { get; set; }
|
||||
|
||||
|
@ -147,4 +158,40 @@ namespace MSFSPopoutPanelManager.UserDataAgent
|
|||
|
||||
public string PanelId { get; set; }
|
||||
}
|
||||
|
||||
public class MsfsGameWindowConfig : ObservableObject
|
||||
{
|
||||
public MsfsGameWindowConfig()
|
||||
{
|
||||
Top = 0;
|
||||
Left = 0;
|
||||
Width = 0;
|
||||
Height = 0;
|
||||
}
|
||||
|
||||
public MsfsGameWindowConfig(int left, int top, int width, int height)
|
||||
{
|
||||
Top = top;
|
||||
Left = left;
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
|
||||
public int Top { get; set; }
|
||||
|
||||
public int Left { get; set; }
|
||||
|
||||
public int Width { get; set; }
|
||||
|
||||
public int Height { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsValid
|
||||
{
|
||||
get
|
||||
{
|
||||
return Width != 0 && Height != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
|
||||
<RootNamespace>MSFSPopoutPanelManager.UserDataAgent</RootNamespace>
|
||||
<Platforms>x64</Platforms>
|
||||
<Version>3.4.2.0</Version>
|
||||
<AssemblyVersion>3.4.2.0</AssemblyVersion>
|
||||
<FileVersion>3.4.2.0</FileVersion>
|
||||
<Version>3.4.3.0</Version>
|
||||
<AssemblyVersion>3.4.3.0</AssemblyVersion>
|
||||
<FileVersion>3.4.3.0</FileVersion>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<DebugType>Embedded</DebugType>
|
||||
<Configurations>Debug;Release;DebugTouchPanel;ReleaseTouchPanel</Configurations>
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
# Version History
|
||||
<hr/>
|
||||
|
||||
## Version 3.4.3
|
||||
* Added ability to remember MSFS game window size and location for aircraft profile when running the game in windows display mode. This new setting is used to resize game window to match original size and location of MSFS game window when panel profile was defined initially. For existing aircraft profile, when running the game in windows display mode, the profile will automatically save MSFS game window position after the first successful pop out.
|
||||
* Added ability to include in-game menu bar panels such as VFR Map, ATC, Checklist, etc to aircraft profile. During the pop out process, if any in-game menu bar panels are in popped out state, they will be included in panel configurations. This feature will only work if in-game menu bar panels are popped out initially and it also rely on MSFS re-opens these panels when flight starts (SU 10+).
|
||||
* Added UI cue to show number circles momentarily when popping out panel to facilitate troubleshooting.
|
||||
|
||||
## Version 3.4.2
|
||||
* Major change in how profile is bound to an aircraft. Previously, a profile is bound to an aircraft livery which requires you to activate binding when switching livery for the same aircraft. With this update, a profile is now bound to an aircraft so you no longer need to perform the binding step when switching livery. As you change active aircraft to fly, all existing livery binding will be automatically converted to aircraft binding if one exists. Also, a profile can still be bound to multiple aircrafts if you so choose such as when flying multiple variations of Cessna 172. This change has been a long awaited request to simplify your profile bindings.
|
||||
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
|
||||
<RootNamespace>MSFSPopoutPanelManager.WebServer</RootNamespace>
|
||||
<Platforms>x64</Platforms>
|
||||
<Version>3.4.2.0</Version>
|
||||
<AssemblyVersion>3.4.2.0</AssemblyVersion>
|
||||
<FileVersion>3.4.2.0</FileVersion>
|
||||
<Version>3.4.3.0</Version>
|
||||
<AssemblyVersion>3.4.3.0</AssemblyVersion>
|
||||
<FileVersion>3.4.3.0</FileVersion>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<DebugType>Embedded</DebugType>
|
||||
<Configurations>Debug;Release;DebugTouchPanel;ReleaseTouchPanel</Configurations>
|
||||
|
|
|
@ -42,13 +42,15 @@ namespace MSFSPopoutPanelManager.WindowsAgent
|
|||
|
||||
public static void LeftClick(int x, int y)
|
||||
{
|
||||
PInvoke.SetCursorPos(x, y);
|
||||
PInvoke.SetCursorPos(x, y); // Need to do this twice to overcome MSFS bug for separating pop out panels
|
||||
PInvoke.SetCursorPos(x, y);
|
||||
Thread.Sleep(300);
|
||||
|
||||
PInvoke.mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0);
|
||||
Thread.Sleep(200);
|
||||
PInvoke.mouse_event(MOUSEEVENTF_LEFTUP, x, y, 0, 0);
|
||||
|
||||
PInvoke.SetCursorPos(x + 5, y);
|
||||
}
|
||||
|
||||
public static void LeftClickFast(int x, int y)
|
||||
|
|
|
@ -123,6 +123,9 @@ namespace MSFSPopoutPanelManager.WindowsAgent
|
|||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr SendMessage(IntPtr hwnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern int ShowCursor(bool bShow);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern bool ShowWindowAsync(HandleRef hwnd, int nCmdShow);
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using MSFSPopoutPanelManager.Shared;
|
||||
using MSFSPopoutPanelManager.UserDataAgent;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
@ -98,6 +99,11 @@ namespace MSFSPopoutPanelManager.WindowsAgent
|
|||
return PInvoke.FindWindowByCaption(IntPtr.Zero, caption);
|
||||
}
|
||||
|
||||
public static string GetWindowCaption(IntPtr hwnd)
|
||||
{
|
||||
return PInvoke.GetWindowText(hwnd);
|
||||
}
|
||||
|
||||
public static Rectangle GetClientRect(IntPtr hwnd)
|
||||
{
|
||||
Rectangle rectangle;
|
||||
|
@ -136,6 +142,23 @@ namespace MSFSPopoutPanelManager.WindowsAgent
|
|||
return count;
|
||||
}
|
||||
|
||||
public static List<IntPtr> GetWindowsByPanelType(List<PanelType> panelTypes)
|
||||
{
|
||||
List<IntPtr> windowHandles = new List<IntPtr>();
|
||||
|
||||
PInvoke.EnumWindows((IntPtr hwnd, int lParam) =>
|
||||
{
|
||||
var panelType = GetWindowPanelType(hwnd);
|
||||
|
||||
if (panelTypes.Contains(panelType))
|
||||
windowHandles.Add(hwnd);
|
||||
|
||||
return true;
|
||||
}, 0);
|
||||
|
||||
return windowHandles;
|
||||
}
|
||||
|
||||
public static PanelType GetWindowPanelType(IntPtr hwnd)
|
||||
{
|
||||
var className = PInvoke.GetClassName(hwnd);
|
||||
|
@ -170,10 +193,70 @@ namespace MSFSPopoutPanelManager.WindowsAgent
|
|||
var panelType = GetWindowPanelType(hwnd);
|
||||
|
||||
if (panelType == PanelType.CustomPopout || panelType == PanelType.MSFSTouchPanel)
|
||||
WindowActionManager.CloseWindow(hwnd);
|
||||
CloseWindow(hwnd);
|
||||
|
||||
return true;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
public static MsfsGameWindowConfig GetMsfsGameWindowLocation()
|
||||
{
|
||||
var msfsGameWindowHandle = GetMsfsGameWindowHandle();
|
||||
var isWindowedMode = IsMsfsGameInWindowedMode(msfsGameWindowHandle);
|
||||
|
||||
if (isWindowedMode)
|
||||
{
|
||||
var windowRect = GetWindowRect(msfsGameWindowHandle);
|
||||
var clientRect = GetClientRect(msfsGameWindowHandle);
|
||||
return new MsfsGameWindowConfig(windowRect.Left, windowRect.Top, clientRect.Width + 16, clientRect.Height + 39);
|
||||
}
|
||||
|
||||
return new MsfsGameWindowConfig(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public static void SetMsfsGameWindowLocation(MsfsGameWindowConfig msfsGameWindowConfig)
|
||||
{
|
||||
var msfsGameWindowHandle = GetMsfsGameWindowHandle();
|
||||
var isWindowedMode = IsMsfsGameInWindowedMode(msfsGameWindowHandle);
|
||||
|
||||
if (isWindowedMode && msfsGameWindowConfig.IsValid)
|
||||
PInvoke.MoveWindow(msfsGameWindowHandle, msfsGameWindowConfig.Left, msfsGameWindowConfig.Top, msfsGameWindowConfig.Width, msfsGameWindowConfig.Height, true);
|
||||
}
|
||||
|
||||
public static bool IsMsfsGameInWindowedMode(IntPtr msfsGameWindowHandle)
|
||||
{
|
||||
if (msfsGameWindowHandle != IntPtr.Zero)
|
||||
{
|
||||
var currentStyle = (uint)PInvoke.GetWindowLong(msfsGameWindowHandle, PInvokeConstant.GWL_STYLE);
|
||||
return (currentStyle & PInvokeConstant.WS_CAPTION) != 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static IntPtr GetMsfsGameWindowHandle()
|
||||
{
|
||||
IntPtr msfsGameWindowHandle = IntPtr.Zero;
|
||||
|
||||
// Get game window handle
|
||||
PInvoke.EnumWindows(new PInvoke.CallBack((IntPtr hwnd, int lParam) =>
|
||||
{
|
||||
var className = PInvoke.GetClassName(hwnd);
|
||||
|
||||
if (className == "AceApp") // MSFS windows designation
|
||||
{
|
||||
var caption = WindowsAgent.PInvoke.GetWindowText(hwnd);
|
||||
|
||||
if (caption.IndexOf("Microsoft Flight Simulator") > -1) // MSFS main game window
|
||||
{
|
||||
msfsGameWindowHandle = hwnd;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}), 0);
|
||||
|
||||
return msfsGameWindowHandle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
|
||||
<RootNamespace>MSFSPopoutPanelManager.WindowsAgent</RootNamespace>
|
||||
<Platforms>x64</Platforms>
|
||||
<Version>3.4.2.0</Version>
|
||||
<AssemblyVersion>3.4.2.0</AssemblyVersion>
|
||||
<FileVersion>3.4.2.0</FileVersion>
|
||||
<Version>3.4.3.0</Version>
|
||||
<AssemblyVersion>3.4.3.0</AssemblyVersion>
|
||||
<FileVersion>3.4.3.0</FileVersion>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<DebugType>Embedded</DebugType>
|
||||
<Configurations>Debug;Release;DebugTouchPanel;ReleaseTouchPanel</Configurations>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
xmlns:shared="clr-namespace:MSFSPopoutPanelManager.Shared;assembly=Shared"
|
||||
mc:Ignorable="d"
|
||||
Title="MSFS Pop Out Panel Manager"
|
||||
Height="710"
|
||||
Height="740"
|
||||
Width="920"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
ResizeMode="CanMinimize"
|
||||
|
@ -72,7 +72,7 @@
|
|||
</Image>
|
||||
</DockPanel>
|
||||
<DockPanel>
|
||||
<StackPanel Name="panelSteps" DockPanel.Dock="Top" Height="545" Background="#FF323C64">
|
||||
<StackPanel Name="panelSteps" DockPanel.Dock="Top" Height="575" Background="#FF323C64">
|
||||
</StackPanel>
|
||||
<WrapPanel DockPanel.Dock="Top" Orientation="Horizontal" Height="70" Background="#FF252523">
|
||||
<Label Content="Status" Margin="5, 10, 5, 5"/>
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace MSFSPopoutPanelManager.WpfApp
|
|||
InitializeComponent();
|
||||
this.Title = title;
|
||||
this.txtMessage.Text = message;
|
||||
this.Topmost = true;
|
||||
}
|
||||
|
||||
private void btnDialogYes_Click(object sender, RoutedEventArgs e)
|
||||
|
|
|
@ -7,15 +7,15 @@
|
|||
Title="PanelCoorOverlay"
|
||||
ResizeMode="NoResize"
|
||||
WindowStyle="None"
|
||||
Height="46"
|
||||
Width="55"
|
||||
Height="30"
|
||||
Width="30"
|
||||
SizeToContent="WidthAndHeight"
|
||||
Background="#01F0F0FF"
|
||||
AllowsTransparency="True"
|
||||
MouseMove="Window_MouseMove"
|
||||
Loaded="Window_Loaded">
|
||||
<Grid>
|
||||
<Label Name="lblPanelIndex" Content="1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
<Image Height="46" Width="55" HorizontalAlignment="Left" VerticalAlignment="Top" Opacity="1" Source="resources/transparent.png"/>
|
||||
<Label Name="lblPanelIndex" Content="1" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="0,0,0,2"/>
|
||||
<Image Height="30" Width="30" HorizontalAlignment="Left" VerticalAlignment="Top" Opacity="1" Source="resources/transparent.png"/>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
|
|
@ -8,8 +8,8 @@ namespace MSFSPopoutPanelManager.WpfApp
|
|||
{
|
||||
public partial class PanelCoorOverlay : Window
|
||||
{
|
||||
private const int TOP_ADJUSTMENT = 23; // half of window height
|
||||
private const int LEFT_ADJUSTMENT = 27; // half of window width
|
||||
private const int TOP_ADJUSTMENT = 15; // half of window height
|
||||
private const int LEFT_ADJUSTMENT = 15; // half of window width
|
||||
private int _xCoor;
|
||||
private int _yCoor;
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
</Window.Resources>
|
||||
<Grid>
|
||||
<DockPanel>
|
||||
<TreeView Width="250" VerticalAlignment="Stretch" DockPanel.Dock="Left">
|
||||
<TreeView Width="240" VerticalAlignment="Stretch" DockPanel.Dock="Left">
|
||||
<TreeView.ItemContainerStyle>
|
||||
<Style TargetType="{x:Type TreeViewItem}">
|
||||
<Setter Property="IsExpanded" Value="True" />
|
||||
|
@ -58,11 +58,12 @@
|
|||
</Style.Resources>
|
||||
</Style>
|
||||
</TreeView.ItemContainerStyle>
|
||||
<TreeViewItem Header="Application Settings" Selected="TreeViewItem_Selected" Margin="0,15,0,10" IsSelected="True"></TreeViewItem>
|
||||
<TreeViewItem Header="Pop Out Settings" Selected="TreeViewItem_Selected" Margin="0,0,0,10"></TreeViewItem>
|
||||
<TreeViewItem Header="Application Settings" Selected="TreeViewItem_Selected" Margin="0,15,0,10" IsSelected="True" Padding="0"></TreeViewItem>
|
||||
<TreeViewItem Header="Auto Pop Out Panel Settings" Selected="TreeViewItem_Selected" Margin="0,0,0,10"></TreeViewItem>
|
||||
<TreeViewItem Header="Track IR Settings" Selected="TreeViewItem_Selected" Margin="0,0,0,10"></TreeViewItem>
|
||||
<TreeViewItem Header="Pop Out Settings" Selected="TreeViewItem_Selected" Margin="0,0,0,10"></TreeViewItem>
|
||||
<TreeViewItem Header="Touch Settings" Selected="TreeViewItem_Selected" Margin="0,0,0,10"></TreeViewItem>
|
||||
<TreeViewItem Header="Track IR Settings" Selected="TreeViewItem_Selected" Margin="0,0,0,10"></TreeViewItem>
|
||||
<TreeViewItem Header="Windowed Mode Settings" Selected="TreeViewItem_Selected" Margin="0,0,0,10"></TreeViewItem>
|
||||
<TreeViewItem Header="MSFS Touch Panel Settings" Selected="TreeViewItem_Selected" Margin="0,0,0,10" Visibility="{Binding Path=AppSettingData.AppSetting.IsEnabledTouchPanelServer, Converter={StaticResource VisibleIfTrueConverter}, Mode=OneWay}"></TreeViewItem>
|
||||
</TreeView>
|
||||
<WrapPanel DockPanel.Dock="Right" Margin="20,10,0,0">
|
||||
|
@ -96,6 +97,23 @@
|
|||
<AccessText TextWrapping="Wrap">Start the application in minimized mode in system tray.</AccessText>
|
||||
</CheckBox>
|
||||
</WrapPanel>
|
||||
|
||||
</WrapPanel>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<WrapPanel Orientation="Vertical" Visibility="{Binding WindowedModeSettingsVisible, Converter={StaticResource VisibleIfTrueConverter}, Mode=OneWay}">
|
||||
<WrapPanel Orientation="Vertical" Margin="0,0,20,20">
|
||||
<TextBlock Style="{StaticResource TextBlockHeading}">Auto Resize MSFS Game Window (Used with Windowed Display Mode only)</TextBlock>
|
||||
<Line Stretch="Fill" Stroke="Gray" X2="1"/>
|
||||
<CheckBox IsChecked="{Binding AppSettingData.AppSetting.AutoResizeMsfsGameWindow, Mode=TwoWay}" >
|
||||
<AccessText TextWrapping="Wrap">Enable automatic resize of MSFS game window when using Windowed Display Mode. When playing the game in Windowed Display Mode, this setting is used to resize game window to match original size
|
||||
and location when panel profile was initially defined. When this setting is first checked, current game window size and location will also be saved automatically.</AccessText>
|
||||
</CheckBox>
|
||||
<TextBlock TextWrapping="Wrap" Margin="28,10,0,0" FontSize="14">
|
||||
To override previously saved MSFS game window size and location, when editing panel location overlay, please also click Override Auto Panning Camera. This will not only save updated panel locations, it will also save MSFS
|
||||
game window size and location to be used on subsequent pop out.
|
||||
</TextBlock>
|
||||
</WrapPanel>
|
||||
</WrapPanel>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
|
@ -282,7 +300,7 @@
|
|||
</WrapPanel>
|
||||
<WrapPanel Visibility="{Binding AppSettingData.AppSetting.TouchPanelSettings.EnableTouchPanelIntegration, Converter={StaticResource VisibleIfTrueConverter}, Mode=OneWay}">
|
||||
<TextBlock FontStyle="Italic">
|
||||
Restart is require for all changes below to take effect.
|
||||
Restart is required for all changes below to take effect.
|
||||
</TextBlock>
|
||||
<WrapPanel Orientation="Vertical" Margin="0,0,20,20">
|
||||
<TextBlock Style="{StaticResource TextBlockHeading}">Enable Use of Arduino</TextBlock>
|
||||
|
|
|
@ -16,6 +16,8 @@ namespace MSFSPopoutPanelManager.WpfApp
|
|||
|
||||
InitializeComponent();
|
||||
this.DataContext = preferencesViewModel;
|
||||
|
||||
_preferencesViewModel.Window = this;
|
||||
}
|
||||
|
||||
public AppSetting AppSetting { get; set; }
|
||||
|
@ -32,6 +34,8 @@ namespace MSFSPopoutPanelManager.WpfApp
|
|||
|
||||
public bool MSFSTouchPanelSettingsVisible { get; set; }
|
||||
|
||||
public bool WindowModeSettingsVisible { get; set; }
|
||||
|
||||
private void TreeViewItem_Selected(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var treeViewItem = (TreeViewItem)e.Source;
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
"WpfApp": {
|
||||
"commandName": "Project",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"ENABLE_XAML_DIAGNOSTICS_SOURCE_INFO": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.6 KiB |
|
@ -16,6 +16,6 @@
|
|||
<SolidColorBrush Color="#FFF0F0F0" Opacity="0.01" />
|
||||
</Window.Background>
|
||||
<Grid>
|
||||
<wv2:WebView2 Name="webView" DefaultBackgroundColor="Transparent" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
|
||||
<wv2:WebView2 Name="webView" DefaultBackgroundColor="Transparent" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Source=""/>
|
||||
</Grid>
|
||||
</mah:MetroWindow>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using MahApps.Metro.Controls;
|
||||
using Microsoft.Web.WebView2.Wpf;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using MSFSPopoutPanelManager.Shared;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -11,8 +11,9 @@ namespace MSFSPopoutPanelManager.WpfApp
|
|||
{
|
||||
private string _planeId;
|
||||
private string _panelId;
|
||||
private CoreWebView2Environment _webView2Environment;
|
||||
|
||||
public TouchPanelWebViewDialog(string planeId, string panelId, string caption, int width, int height)
|
||||
public TouchPanelWebViewDialog(string planeId, string panelId, string caption, int width, int height, CoreWebView2Environment environment)
|
||||
{
|
||||
InitializeComponent();
|
||||
//this.Topmost = true;
|
||||
|
@ -22,21 +23,22 @@ namespace MSFSPopoutPanelManager.WpfApp
|
|||
|
||||
_planeId = planeId;
|
||||
_panelId = panelId;
|
||||
_webView2Environment = environment;
|
||||
|
||||
Loaded += TouchPanelWebViewDialog_Loaded;
|
||||
}
|
||||
|
||||
private void TouchPanelWebViewDialog_Loaded(object sender, System.Windows.RoutedEventArgs e)
|
||||
private async void TouchPanelWebViewDialog_Loaded(object sender, System.Windows.RoutedEventArgs e)
|
||||
{
|
||||
StartWebView(webView);
|
||||
await webView.EnsureCoreWebView2Async(_webView2Environment);
|
||||
|
||||
// This somehow fixes webview did not maximize correctly when the host WPF dialog is maximized
|
||||
WindowExtensions.FixWindowMaximizeCropping(this);
|
||||
if (webView != null && webView.CoreWebView2 != null)
|
||||
{
|
||||
webView.CoreWebView2.Navigate($"{Constants.WEB_HOST_URI}/{_planeId.ToLower()}/{_panelId.ToLower()}");
|
||||
}
|
||||
|
||||
private void StartWebView(WebView2 webView)
|
||||
{
|
||||
webView.Source = new Uri($"{Constants.WEB_HOST_URI}/{_planeId.ToLower()}/{_panelId.ToLower()}");
|
||||
// This fixes webview which does not maximize correctly when host WPF dialog is maximized
|
||||
WindowExtensions.FixWindowMaximizeCropping(this);
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:c="clr-namespace:CalcBinding;assembly=CalcBinding"
|
||||
mc:Ignorable="d"
|
||||
Height="545"
|
||||
Height="575"
|
||||
Width="920"
|
||||
Background="#FF323A64">
|
||||
<UserControl.Resources>
|
||||
|
@ -45,7 +45,7 @@
|
|||
<Image Width="22" Height="22" VerticalAlignment="Center" Source="Resources\info_icon.png"></Image>
|
||||
</controls:Tile>
|
||||
</WrapPanel>
|
||||
<DataGrid Name="PanelConfigGrid" HorizontalAlignment="Center" Width="882" Height="430" Margin="0 10 0 0" AutoGenerateColumns="False" CanUserResizeColumns="False" HorizontalScrollBarVisibility="Disabled"
|
||||
<DataGrid Name="PanelConfigGrid" HorizontalAlignment="Center" Width="882" Height="460" Margin="0 10 0 0" AutoGenerateColumns="False" CanUserResizeColumns="False" HorizontalScrollBarVisibility="Disabled"
|
||||
CanUserReorderColumns="False" CanUserResizeRows="False" HorizontalGridLinesBrush="#B9B9B9" VerticalGridLinesBrush="#B9B9B9" GridLinesVisibility="Horizontal" SelectionUnit="Cell"
|
||||
BorderThickness="1" CanUserAddRows="False" CanUserSortColumns="False" KeyboardNavigation.TabNavigation="None" KeyboardNavigation.IsTabStop="False"
|
||||
ItemsSource="{Binding ProfileData.ActiveProfile.PanelConfigs}" HeadersVisibility="Column" KeyboardNavigation.DirectionalNavigation="Local" MouseDown="PanelConfigGrid_MouseDown">
|
||||
|
@ -211,7 +211,7 @@
|
|||
SourceUpdated="GridData_SourceUpdated"
|
||||
IsChecked="{Binding HideTitlebar, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{c:Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=1}, Path='!DataContext.ProfileData.ActiveProfile.IsLocked '}"
|
||||
IsHitTestVisible="{c:Binding Path='!FullScreen and IsCustomPopOut'}"/>
|
||||
IsHitTestVisible="{c:Binding Path='!FullScreen and (IsCustomPopOut or IsBuiltInPopOut)'}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
@ -222,7 +222,7 @@
|
|||
SourceUpdated="GridData_SourceUpdated"
|
||||
IsChecked="{Binding FullScreen, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{c:Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=1}, Path='!DataContext.ProfileData.ActiveProfile.IsLocked'}"
|
||||
IsHitTestVisible="{c:Binding Path='IsCustomPopOut'}"/>
|
||||
IsHitTestVisible="{c:Binding Path='IsCustomPopOut or IsBuiltInPopOut'}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
@ -233,7 +233,7 @@
|
|||
SourceUpdated="GridData_SourceUpdated"
|
||||
IsChecked="{Binding TouchEnabled, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{c:Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=1}, Path='!DataContext.ProfileData.ActiveProfile.IsLocked'}"
|
||||
IsHitTestVisible="{c:Binding Path='!FullScreen and IsCustomPopOut'}"/>
|
||||
IsHitTestVisible="{c:Binding Path='!FullScreen and (IsCustomPopOut or IsBuiltInPopOut)'}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
@ -244,7 +244,7 @@
|
|||
SourceUpdated="GridData_SourceUpdated"
|
||||
IsChecked="{Binding DisableGameRefocus, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{c:Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=1}, Path='!DataContext.ProfileData.ActiveProfile.IsLocked'}"
|
||||
IsHitTestVisible="{c:Binding Path='!FullScreen and IsCustomPopOut and TouchEnabled'}"/>
|
||||
IsHitTestVisible="{c:Binding Path='!FullScreen and (IsCustomPopOut or IsBuiltInPopOut) and TouchEnabled'}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
mc:Ignorable="d"
|
||||
Height="545"
|
||||
Height="575"
|
||||
Width="920"
|
||||
Background="#FF323A64">
|
||||
<UserControl.Resources>
|
||||
|
@ -77,6 +77,7 @@
|
|||
<Button Content="-" ToolTip="Delete Binding" Margin="10,0,0,0" Width="40" Command="{Binding DeleteProfileBindingCommand}"/>
|
||||
</WrapPanel>
|
||||
<CheckBox Margin="10,5,0,0" Content="Power on required to pop out panels on cold start (G1000 / NXi Only)" IsChecked="{Binding ProfileData.ActiveProfile.PowerOnRequiredForColdStart}" Command="{Binding SetPowerOnRequiredCommand}" />
|
||||
<CheckBox Margin="10,5,0,0" Content="Include in-game menu bar panels (VFR Map, Checklist, ATC, etc)" IsChecked="{Binding ProfileData.ActiveProfile.IncludeInGamePanels}" Command="{Binding SetIncludeInGamePanelsCommand}" />
|
||||
<WrapPanel Name="TouchPanelConfigurationPanel" Orientation="Horizontal" Margin="0,10,0,0" Visibility="{Binding AppSettingData.AppSetting.IsEnabledTouchPanelServer, Converter={StaticResource VisibleIfTrueConverter}, Mode=OneWay}" >
|
||||
<Label Content="Open MSFS touch panel when flight session starts" Margin="5,0,0,0" />
|
||||
<Button Content="+" ToolTip="Add Binding" Margin="94,0,0,0" Width="40" Command="{Binding OpenTouchPanelBindingCommand}"/>
|
||||
|
@ -114,7 +115,7 @@
|
|||
</WrapPanel>
|
||||
<DockPanel DockPanel.Dock="Right" Width="325" HorizontalAlignment="Center">
|
||||
<Label DockPanel.Dock="Top" Content="Panel Locations" HorizontalAlignment="Center" Margin="0,10,0,0"/>
|
||||
<DataGrid DockPanel.Dock="Top" HorizontalAlignment="Center" Width="290" Height="435" AutoGenerateColumns="False" CanUserResizeColumns="False" HorizontalScrollBarVisibility="Disabled"
|
||||
<DataGrid DockPanel.Dock="Top" HorizontalAlignment="Center" Width="290" Height="465" AutoGenerateColumns="False" CanUserResizeColumns="False" HorizontalScrollBarVisibility="Disabled"
|
||||
CanUserReorderColumns="False" CanUserResizeRows="False" IsReadOnly="True" HorizontalGridLinesBrush="#B9B9B9" VerticalGridLinesBrush="#B9B9B9" GridLinesVisibility="Horizontal" BorderThickness="1"
|
||||
CanUserAddRows="False" CanUserSortColumns="False" ItemsSource="{Binding ProfileData.ActiveProfile.PanelSourceCoordinates}">
|
||||
<DataGrid.CellStyle>
|
||||
|
|
|
@ -16,6 +16,16 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
|
|||
return (bool)dialog.ShowDialog();
|
||||
}
|
||||
|
||||
public static bool ConfirmDialog(string title, string message, Window owner)
|
||||
{
|
||||
var dialog = new ConfirmationDialog(title, message);
|
||||
dialog.Owner = owner;
|
||||
dialog.Topmost = true;
|
||||
dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||
|
||||
return (bool)dialog.ShowDialog();
|
||||
}
|
||||
|
||||
public static AddProfileDialogResult AddProfileDialog(List<Profile> profiles)
|
||||
{
|
||||
var dialog = new AddProfileDialog(profiles);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using MSFSPopoutPanelManager.Orchestration;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using MSFSPopoutPanelManager.Orchestration;
|
||||
using MSFSPopoutPanelManager.Shared;
|
||||
using MSFSPopoutPanelManager.UserDataAgent;
|
||||
using MSFSPopoutPanelManager.WindowsAgent;
|
||||
|
@ -12,12 +13,13 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
|
|||
{
|
||||
private MainOrchestrator _orchestrator;
|
||||
private bool _minimizeForPopOut;
|
||||
private CoreWebView2Environment _coreWebView2Environment;
|
||||
|
||||
public OrchestratorHelper(MainOrchestrator orchestrator)
|
||||
{
|
||||
_orchestrator = orchestrator;
|
||||
|
||||
_orchestrator.PanelSource.onOverlayShowed += HandleShowOverlay;
|
||||
_orchestrator.PanelSource.OnOverlayShowed += HandleShowOverlay;
|
||||
_orchestrator.PanelSource.OnLastOverlayRemoved += (sender, e) => HandleRemovePanelSourceOverlay(false);
|
||||
_orchestrator.PanelSource.OnAllOverlaysRemoved += (sender, e) => HandleRemovePanelSourceOverlay(true);
|
||||
_orchestrator.PanelSource.OnSelectionStarted += HandlePanelSelectionStarted;
|
||||
|
@ -26,6 +28,7 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
|
|||
_orchestrator.PanelPopOut.OnPopOutStarted += HandleOnPopOutStarted;
|
||||
_orchestrator.PanelPopOut.OnPopOutCompleted += HandleOnPopOutCompleted;
|
||||
_orchestrator.PanelPopOut.OnTouchPanelOpened += HandleOnTouchPanelOpened;
|
||||
_orchestrator.PanelPopOut.OnPanelSourceOverlayFlashed += HandleOnPanelSourceOverlayFlashed;
|
||||
|
||||
StatusMessageWriter.OnStatusMessage += HandleOnStatusMessage;
|
||||
}
|
||||
|
@ -72,6 +75,16 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
|
|||
AddPanelCoorOverlay(e);
|
||||
}
|
||||
|
||||
private void HandleOnPanelSourceOverlayFlashed(object sender, PanelSourceCoordinate e)
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
AddPanelCoorOverlay(e);
|
||||
System.Threading.Thread.Sleep(750);
|
||||
HandleRemovePanelSourceOverlay(true);
|
||||
});
|
||||
}
|
||||
|
||||
private void HandleRemovePanelSourceOverlay(bool removeAll)
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
|
@ -113,9 +126,15 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
|
|||
|
||||
private void HandleOnTouchPanelOpened(object sender, TouchPanelOpenEventArg e)
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
Application.Current.Dispatcher.Invoke(async () =>
|
||||
{
|
||||
TouchPanelWebViewDialog window = new TouchPanelWebViewDialog(e.PlaneId, e.PanelId, e.Caption, e.Width, e.Height);
|
||||
if (_coreWebView2Environment == null)
|
||||
{
|
||||
var options = new CoreWebView2EnvironmentOptions("--disable-web-security");
|
||||
_coreWebView2Environment = await CoreWebView2Environment.CreateAsync(null, null, options);
|
||||
}
|
||||
|
||||
TouchPanelWebViewDialog window = new TouchPanelWebViewDialog(e.PlaneId, e.PanelId, e.Caption, e.Width, e.Height, _coreWebView2Environment);
|
||||
window.Show();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -45,17 +45,23 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
|
|||
.ObservesProperty(() => ProfileData.ActiveProfile)
|
||||
.ObservesProperty(() => FlightSimData.IsSimulatorStarted);
|
||||
|
||||
SetIncludeInGamePanelsCommand = new DelegateCommand(() => ProfileData.WriteProfiles(), () => FlightSimData.HasCurrentMsfsAircraft && ProfileData.HasActiveProfile && FlightSimData.IsSimulatorStarted)
|
||||
.ObservesProperty(() => FlightSimData.HasCurrentMsfsAircraft)
|
||||
.ObservesProperty(() => ProfileData.ActiveProfile)
|
||||
.ObservesProperty(() => FlightSimData.IsSimulatorStarted);
|
||||
|
||||
StartPanelSelectionCommand = new DelegateCommand(OnStartPanelSelection, () => FlightSimData.HasCurrentMsfsAircraft && ProfileData.HasActiveProfile && ProfileData.ActiveProfile != null && FlightSimData.IsSimulatorStarted && FlightSimData.IsInCockpit)
|
||||
.ObservesProperty(() => FlightSimData.HasCurrentMsfsAircraft)
|
||||
.ObservesProperty(() => ProfileData.ActiveProfile)
|
||||
.ObservesProperty(() => FlightSimData.IsSimulatorStarted)
|
||||
.ObservesProperty(() => FlightSimData.IsInCockpit);
|
||||
|
||||
StartPopOutCommand = new DelegateCommand(OnStartPopOut, () => FlightSimData.HasCurrentMsfsAircraft && ProfileData.HasActiveProfile && (ProfileData.ActiveProfile.PanelSourceCoordinates.Count > 0 || ProfileData.ActiveProfile.TouchPanelBindings.Count > 0) && FlightSimData.IsSimulatorStarted && FlightSimData.IsInCockpit)
|
||||
StartPopOutCommand = new DelegateCommand(OnStartPopOut, () => FlightSimData.HasCurrentMsfsAircraft && ProfileData.HasActiveProfile && (ProfileData.ActiveProfile.PanelSourceCoordinates.Count > 0 || ProfileData.ActiveProfile.TouchPanelBindings.Count > 0 || ProfileData.ActiveProfile.IncludeInGamePanels) && FlightSimData.IsSimulatorStarted && FlightSimData.IsInCockpit)
|
||||
.ObservesProperty(() => FlightSimData.HasCurrentMsfsAircraft)
|
||||
.ObservesProperty(() => ProfileData.ActiveProfile)
|
||||
.ObservesProperty(() => ProfileData.ActiveProfile.PanelSourceCoordinates.Count)
|
||||
.ObservesProperty(() => ProfileData.ActiveProfile.TouchPanelBindings.Count)
|
||||
.ObservesProperty(() => ProfileData.ActiveProfile.IncludeInGamePanels)
|
||||
.ObservesProperty(() => FlightSimData.IsSimulatorStarted)
|
||||
.ObservesProperty(() => FlightSimData.IsInCockpit);
|
||||
|
||||
|
@ -94,6 +100,8 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
|
|||
|
||||
public DelegateCommand SetPowerOnRequiredCommand { get; private set; }
|
||||
|
||||
public DelegateCommand SetIncludeInGamePanelsCommand { get; private set; }
|
||||
|
||||
public DelegateCommand StartPanelSelectionCommand { get; private set; }
|
||||
|
||||
public DelegateCommand StartPopOutCommand { get; private set; }
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using MSFSPopoutPanelManager.Orchestration;
|
||||
using MSFSPopoutPanelManager.Shared;
|
||||
using Prism.Commands;
|
||||
using System.Windows;
|
||||
|
||||
namespace MSFSPopoutPanelManager.WpfApp.ViewModel
|
||||
{
|
||||
|
@ -20,6 +21,8 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
|
|||
SectionSelectCommand = new DelegateCommand<object>(OnSectionSelected);
|
||||
}
|
||||
|
||||
public Window Window { get; set; }
|
||||
|
||||
public DelegateCommand<object> SectionSelectCommand { get; private set; }
|
||||
|
||||
public AppSettingData AppSettingData { get { return _orchestrator.AppSettingData; } }
|
||||
|
@ -36,6 +39,8 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
|
|||
|
||||
public bool MSFSTouchPanelSettingsVisible { get; private set; }
|
||||
|
||||
public bool WindowedModeSettingsVisible { get; private set; }
|
||||
|
||||
private void OnSectionSelected(object commandParameter)
|
||||
{
|
||||
ApplicationSettingsVisible = false;
|
||||
|
@ -44,6 +49,7 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
|
|||
TrackIRSettingsVisible = false;
|
||||
TouchSettingsVisible = false;
|
||||
MSFSTouchPanelSettingsVisible = false;
|
||||
WindowedModeSettingsVisible = false;
|
||||
|
||||
switch (commandParameter.ToString())
|
||||
{
|
||||
|
@ -65,6 +71,9 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
|
|||
case "MSFS Touch Panel Settings":
|
||||
MSFSTouchPanelSettingsVisible = true;
|
||||
break;
|
||||
case "Windowed Mode Settings":
|
||||
WindowedModeSettingsVisible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
<RootNamespace>MSFSPopoutPanelManager.WpfApp</RootNamespace>
|
||||
<ApplicationIcon>logo.ico</ApplicationIcon>
|
||||
<Platforms>x64</Platforms>
|
||||
<Version>3.4.2.0</Version>
|
||||
<AssemblyVersion>3.4.2.0</AssemblyVersion>
|
||||
<FileVersion>3.4.2.0</FileVersion>
|
||||
<Version>3.4.3.0</Version>
|
||||
<AssemblyVersion>3.4.3.0</AssemblyVersion>
|
||||
<FileVersion>3.4.3.0</FileVersion>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<DebugType>embedded</DebugType>
|
||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||
|
@ -89,7 +89,7 @@
|
|||
<PackageReference Include="WindowsHook" Version="1.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="3.1.27" Condition=" '$(Configuration)' == 'ReleaseTouchPanel' Or '$(Configuration)' == 'DebugTouchPanel' " />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.7" Condition=" '$(Configuration)' == 'ReleaseTouchPanel' Or '$(Configuration)' == 'DebugTouchPanel' " />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1264.42" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1293.44" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,39 +1,21 @@
|
|||
Version 3.4.2.0
|
||||
Version 3.4.3.0
|
||||
|
||||
This release is optional and please feel to skip this update.
|
||||
|
||||
Change Log:
|
||||
|
||||
* Major change in how profile is bound to an aircraft. Previously, a profile is bound to an
|
||||
aircraft livery which requires you to activate binding when switching livery for the same
|
||||
aircraft. With this update, a profile is now bound to an aircraft so you no longer need to
|
||||
perform the binding step when switching livery. As you change active aircraft to fly, all
|
||||
existing livery binding will be automatically converted to aircraft binding if one exists.
|
||||
Also, a profile can still be bound to multiple aircrafts if you so choose such as when
|
||||
flying multiple variations of Cessna 172. This change has been a long awaited request to
|
||||
simplify your profile bindings.
|
||||
* Added ability to remember MSFS game window size and location for aircraft profile when
|
||||
running the game in windows display mode. This new setting is used to resize game window to
|
||||
match original size and location of MSFS game window when panel profile was defined
|
||||
initially. For existing aircraft profile, when running the game in windows display mode,
|
||||
the profile will automatically save MSFS game window position after the first successful
|
||||
pop out.
|
||||
|
||||
* Added auto assignment of aircraft binding for a newly created profile if the active
|
||||
aircraft has no previous profile binding specified.
|
||||
* Added ability to include in-game menu bar panels such as VFR Map, ATC, Checklist, etc to
|
||||
aircraft profile. During the pop out process, if any in-game menu bar panels are in popped
|
||||
out state, they will be included in panel configurations. This feature will only work if
|
||||
in-game menu bar panels are popped out initially and it also rely on MSFS re-opens these
|
||||
panels when flight starts (SU 10+).
|
||||
|
||||
* Added new keyboard shortcuts to move and resize pop outs. Please click on a new
|
||||
information icon in the upper right corner of panel configuration screen for instruction in
|
||||
how to use these new keyboard shortcuts.
|
||||
|
||||
* Added new setting to minimize pop out manager after panels have been popped out.
|
||||
|
||||
* Added work around for SU10 Beta issue when after panel separations, panels' size become
|
||||
so big and they block most of the game window for lower resolution screen and prevented Pop
|
||||
Out Panel Manager from popping out the next panel.
|
||||
|
||||
* Made improvements to how panels are separated during pop out process.
|
||||
|
||||
* Fixed an issue when adjusting position and size of a pop out panel on some PC
|
||||
configuration.
|
||||
|
||||
Known issue:
|
||||
|
||||
* When changing the width or height of a pop up that has Hide Title Bar enable, it will
|
||||
sometime break the Hide Title Bar setting and the only way to fix this is to re-pop out the
|
||||
panel. Currently, this is a bug in MSFS in how it handles the sizing and rendering of pop
|
||||
outs window.
|
||||
* Added UI cue to show number circles momentarily when popping out panel to facilitate
|
||||
troubleshooting.
|
Loading…
Reference in a new issue