├── .gitignore ├── CHANGELOG.md ├── LICENSE.GPL.txt ├── LICENSE.LGPL.txt ├── LICENSE.txt ├── README.md ├── build ├── Invoke-MsBuild.psm1 ├── Make-Version.ps1 ├── Merge-Tokens.ps1 ├── build.ps1 └── version.ps1 ├── docs ├── .gitignore ├── .nojekyll ├── CNAME ├── Doxyfile ├── DoxygenLayout.xml ├── Logo-square.png ├── Logo.png ├── customdoxygen.css ├── doxyawesome │ ├── doxygen-awesome-darkmode-toggle.js │ ├── doxygen-awesome-paragraph-link.js │ └── doxygen-awesome.css ├── footer.html ├── header.html ├── version.Doxyfile └── version.Doxyfile.in └── src ├── .editorconfig ├── README.md ├── Testing ├── CPP_BasicConsole │ ├── CPP_BasicConsole.cpp │ ├── CPP_BasicConsole.vcxproj │ ├── LICENSE.txt │ └── README.md ├── CS_BasicConsole │ ├── CS_BasicConsole.csproj │ ├── Directory.Build.props │ ├── LICENSE.txt │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ └── README.md └── Py_BasicConsole │ ├── LICENSE.txt │ ├── Py_BasicConsole.py │ ├── Py_BasicConsole.pyproj │ ├── README.md │ └── app.runtime.json ├── WASimClient ├── LICENSE.GPL.txt ├── LICENSE.LGPL.txt ├── LICENSE.txt ├── README.md ├── WASimClient.cpp ├── WASimClient.vcxproj ├── client_conf.ini └── dllmain.cpp ├── WASimClient_CLI ├── AssemblyInfo.cpp ├── AssemblyInfo.cpp.in ├── Enums.h ├── LICENSE.GPL.txt ├── LICENSE.LGPL.txt ├── LICENSE.txt ├── README.md ├── Structs.h ├── WASimClient_CLI.cpp ├── WASimClient_CLI.h ├── WASimClient_CLI.vcxproj ├── WASimCommander_CLI.h └── deps.manifest ├── WASimCommander.sln ├── WASimModule ├── LICENSE.txt ├── README.md ├── WASimModule.cpp ├── WASimModule.vcxproj ├── WASimModuleProject │ └── WASimCommander-Module │ │ ├── .gitignore │ │ ├── PackageDefinitions │ │ ├── wasimcommander-module.xml │ │ ├── wasimcommander-module.xml.in │ │ └── wasimcommander-module │ │ │ └── ContentInfo │ │ │ └── Thumbnail.jpg │ │ ├── PackageSources │ │ └── WASimModule │ │ │ └── .gitinclude │ │ └── WASimCommander-Module.xml ├── server_conf.ini └── token_vars.h ├── WASimUI ├── DocImports.h ├── DocImportsBrowser.h ├── DocImportsBrowser.ui ├── EventsModel.h ├── LICENSE.txt ├── LogConsole.cpp ├── LogConsole.h ├── LogConsole.ui ├── LogRecordsModel.h ├── README.md ├── RequestsExport.cpp ├── RequestsExport.h ├── RequestsExport.ui ├── RequestsFormat.h ├── RequestsModel.h ├── RequestsTableView.h ├── SimConnect.cfg ├── Utils.h ├── WASimUI.aps ├── WASimUI.cpp ├── WASimUI.h ├── WASimUI.qrc ├── WASimUI.rc ├── WASimUI.ui ├── WASimUI.vcxproj ├── WASimUI.vcxproj.metaproj ├── main.cpp ├── model │ ├── AlphanumComparer.h │ └── MultiColumnProxyModel.h ├── resources │ ├── IcoMoon-Free.ttf │ ├── IcoMoon.LICENSE.txt │ ├── MSFS_SDK_Doc_Import.sqlite3 │ ├── MaterialIcons-Regular.ttf │ ├── MaterialIcons.LICENSE.txt │ ├── WASim-Logo_96.png │ ├── WASim.ico │ ├── icomooon.cmap.json │ ├── materialicons.cmap.json │ └── style.css └── widgets │ ├── ActionPushButton.cpp │ ├── ActionPushButton.h │ ├── BuddyLabel.h │ ├── CustomTableView.h │ ├── DataComboBox.h │ ├── DeletableItemsComboBox.h │ ├── FilterLineEdit.cpp │ ├── FilterLineEdit.h │ ├── FilterTableHeader.cpp │ ├── FilterTableHeader.h │ ├── MultisortTableView.h │ └── Widgets.h ├── common.props ├── include ├── LICENSE.GPL.txt ├── LICENSE.LGPL.txt ├── LICENSE.txt ├── README.md ├── WASimCommander.h ├── client │ ├── WASimClient.h │ ├── enums.h │ ├── enums_impl.h │ ├── exports.h │ └── structs.h ├── enums.h ├── enums_impl.h ├── global.h ├── wasim_version.h └── wasim_version.in └── shared ├── SimConnectHelper.h ├── SimConnectRequestTracker.h ├── inipp.h ├── key_events.h ├── logfault.h └── utilities.h /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .vs*/ 3 | *.code* 4 | src/build/ 5 | bin/ 6 | obj/ 7 | dist/ 8 | *.user 9 | *.filters 10 | *.log 11 | * - Copy 12 | __*.* 13 | _bak*/ 14 | .bak*/ 15 | x64/ 16 | x86/ 17 | Win32/ 18 | CMake* 19 | -------------------------------------------------------------------------------- /LICENSE.LGPL.txt: -------------------------------------------------------------------------------- 1 | /*! \page LICENSE.LGPL.txt LICENSE.LGPL.txt 2 | \verbatim 3 | 4 | GNU LESSER GENERAL PUBLIC LICENSE 5 | Version 3, 29 June 2007 6 | 7 | Copyright (C) 2007 Free Software Foundation, Inc. 8 | Everyone is permitted to copy and distribute verbatim copies 9 | of this license document, but changing it is not allowed. 10 | 11 | 12 | This version of the GNU Lesser General Public License incorporates 13 | the terms and conditions of version 3 of the GNU General Public 14 | License, supplemented by the additional permissions listed below. 15 | 16 | 0. Additional Definitions. 17 | 18 | As used herein, "this License" refers to version 3 of the GNU Lesser 19 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 20 | General Public License. 21 | 22 | "The Library" refers to a covered work governed by this License, 23 | other than an Application or a Combined Work as defined below. 24 | 25 | An "Application" is any work that makes use of an interface provided 26 | by the Library, but which is not otherwise based on the Library. 27 | Defining a subclass of a class defined by the Library is deemed a mode 28 | of using an interface provided by the Library. 29 | 30 | A "Combined Work" is a work produced by combining or linking an 31 | Application with the Library. The particular version of the Library 32 | with which the Combined Work was made is also called the "Linked 33 | Version". 34 | 35 | The "Minimal Corresponding Source" for a Combined Work means the 36 | Corresponding Source for the Combined Work, excluding any source code 37 | for portions of the Combined Work that, considered in isolation, are 38 | based on the Application, and not on the Linked Version. 39 | 40 | The "Corresponding Application Code" for a Combined Work means the 41 | object code and/or source code for the Application, including any data 42 | and utility programs needed for reproducing the Combined Work from the 43 | Application, but excluding the System Libraries of the Combined Work. 44 | 45 | 1. Exception to Section 3 of the GNU GPL. 46 | 47 | You may convey a covered work under sections 3 and 4 of this License 48 | without being bound by section 3 of the GNU GPL. 49 | 50 | 2. Conveying Modified Versions. 51 | 52 | If you modify a copy of the Library, and, in your modifications, a 53 | facility refers to a function or data to be supplied by an Application 54 | that uses the facility (other than as an argument passed when the 55 | facility is invoked), then you may convey a copy of the modified 56 | version: 57 | 58 | a) under this License, provided that you make a good faith effort to 59 | ensure that, in the event an Application does not supply the 60 | function or data, the facility still operates, and performs 61 | whatever part of its purpose remains meaningful, or 62 | 63 | b) under the GNU GPL, with none of the additional permissions of 64 | this License applicable to that copy. 65 | 66 | 3. Object Code Incorporating Material from Library Header Files. 67 | 68 | The object code form of an Application may incorporate material from 69 | a header file that is part of the Library. You may convey such object 70 | code under terms of your choice, provided that, if the incorporated 71 | material is not limited to numerical parameters, data structure 72 | layouts and accessors, or small macros, inline functions and templates 73 | (ten or fewer lines in length), you do both of the following: 74 | 75 | a) Give prominent notice with each copy of the object code that the 76 | Library is used in it and that the Library and its use are 77 | covered by this License. 78 | 79 | b) Accompany the object code with a copy of the GNU GPL and this license 80 | document. 81 | 82 | 4. Combined Works. 83 | 84 | You may convey a Combined Work under terms of your choice that, 85 | taken together, effectively do not restrict modification of the 86 | portions of the Library contained in the Combined Work and reverse 87 | engineering for debugging such modifications, if you also do each of 88 | the following: 89 | 90 | a) Give prominent notice with each copy of the Combined Work that 91 | the Library is used in it and that the Library and its use are 92 | covered by this License. 93 | 94 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 95 | document. 96 | 97 | c) For a Combined Work that displays copyright notices during 98 | execution, include the copyright notice for the Library among 99 | these notices, as well as a reference directing the user to the 100 | copies of the GNU GPL and this license document. 101 | 102 | d) Do one of the following: 103 | 104 | 0) Convey the Minimal Corresponding Source under the terms of this 105 | License, and the Corresponding Application Code in a form 106 | suitable for, and under terms that permit, the user to 107 | recombine or relink the Application with a modified version of 108 | the Linked Version to produce a modified Combined Work, in the 109 | manner specified by section 6 of the GNU GPL for conveying 110 | Corresponding Source. 111 | 112 | 1) Use a suitable shared library mechanism for linking with the 113 | Library. A suitable mechanism is one that (a) uses at run time 114 | a copy of the Library already present on the user's computer 115 | system, and (b) will operate properly with a modified version 116 | of the Library that is interface-compatible with the Linked 117 | Version. 118 | 119 | e) Provide Installation Information, but only if you would otherwise 120 | be required to provide such information under section 6 of the 121 | GNU GPL, and only to the extent that such information is 122 | necessary to install and execute a modified version of the 123 | Combined Work produced by recombining or relinking the 124 | Application with a modified version of the Linked Version. (If 125 | you use option 4d0, the Installation Information must accompany 126 | the Minimal Corresponding Source and Corresponding Application 127 | Code. If you use option 4d1, you must provide the Installation 128 | Information in the manner specified by section 6 of the GNU GPL 129 | for conveying Corresponding Source.) 130 | 131 | 5. Combined Libraries. 132 | 133 | You may place library facilities that are a work based on the 134 | Library side by side in a single library together with other library 135 | facilities that are not Applications and are not covered by this 136 | License, and convey such a combined library under terms of your 137 | choice, if you do both of the following: 138 | 139 | a) Accompany the combined library with a copy of the same work based 140 | on the Library, uncombined with any other library facilities, 141 | conveyed under the terms of this License. 142 | 143 | b) Give prominent notice with the combined library that part of it 144 | is a work based on the Library, and explaining where to find the 145 | accompanying uncombined form of the same work. 146 | 147 | 6. Revised Versions of the GNU Lesser General Public License. 148 | 149 | The Free Software Foundation may publish revised and/or new versions 150 | of the GNU Lesser General Public License from time to time. Such new 151 | versions will be similar in spirit to the present version, but may 152 | differ in detail to address new problems or concerns. 153 | 154 | Each version is given a distinguishing version number. If the 155 | Library as you received it specifies that a certain numbered version 156 | of the GNU Lesser General Public License "or any later version" 157 | applies to it, you have the option of following the terms and 158 | conditions either of that published version or of any later version 159 | published by the Free Software Foundation. If the Library as you 160 | received it does not specify a version number of the GNU Lesser 161 | General Public License, you may choose any version of the GNU Lesser 162 | General Public License ever published by the Free Software Foundation. 163 | 164 | If the Library as you received it specifies that a proxy can decide 165 | whether future versions of the GNU Lesser General Public License shall 166 | apply, that proxy's public statement of acceptance of any version is 167 | permanent authorization for you to choose that version for the 168 | Library. 169 | 170 | \endverbatim */ -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! \page LICENSE.txt LICENSE.txt 2 | \verbatim 3 | 4 | WASimCommander Project 5 | 6 | COPYRIGHT: Maxim Paperno; All Rights Reserved. 7 | 8 | #### Overall API and Client Library Components: 9 | Dual licensed under the terms of either the GNU General Public License (**GPL**) 10 | or the GNU Lesser General Public License (**LGPL**), as published by the Free Software 11 | Foundation, either **version 3** of the Licenses, or (at your option) any later version. 12 | 13 | #### WASM Module Server, GUI, and Console App Components: 14 | Licensed under the terms of the GNU General Public License (**GPL**) as published by 15 | the Free Software Foundation, either **version 3** of the License, or (at your option) 16 | any later version. 17 | 18 | #### General: 19 | This program is distributed in the hope that it will be useful, 20 | but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | GNU General Public License for more details. 23 | 24 | Copies of the GNU GPL and LGPL are included with this project 25 | and are available at . 26 | 27 | Except as contained in this copyright notice, the names of the authors or 28 | their institutions shall not be used in advertising or otherwise to 29 | promote the sale, use, or other dealings in, any product using this 30 | Software, or any derivative of this Software, without prior written 31 | authorization from the authors. 32 | 33 | This project may also use 3rd-party Open Source software under the terms 34 | of their respective licenses. The copyright notice above does not apply 35 | to any 3rd-party components used within. 36 | 37 | \endverbatim */ 38 | -------------------------------------------------------------------------------- /build/Make-Version.ps1: -------------------------------------------------------------------------------- 1 | . .\version.ps1 2 | . .\Merge-Tokens.ps1 3 | 4 | function Make-Version { 5 | [CmdletBinding()] 6 | param( 7 | [string]$SrcPath = "..\src", 8 | [string]$DocPath = "..\docs" 9 | ) 10 | 11 | $gitver = & { git rev-parse --short=8 HEAD } 2>&1 | % ToString 12 | #$gitver = & { git describe --tags --long } 2>&1 | % ToString 13 | Write-Host "Git returned version: $gitver" 14 | if ($gitver.length -eq 8) { 15 | $VER_COMIT = $gitver.ToUpper() 16 | } 17 | 18 | $Tokens = New-Object -TypeName "System.Collections.Hashtable" 19 | $Tokens.Add("VER_MAJOR", $VER_MAJOR) 20 | $Tokens.Add("VER_MINOR", $VER_MINOR) 21 | $Tokens.Add("VER_PATCH", $VER_PATCH) 22 | $Tokens.Add("VER_BUILD", $VER_BUILD) 23 | $Tokens.Add("VER_COMIT", "0x{0:X8}" -f $VER_COMIT) 24 | $Tokens.Add("VER_NAME", $VER_NAME) 25 | $Tokens.Add("VERSION", "0x{0:X8}" -f ($VER_MAJOR -shl 24 -bor $VER_MINOR -shl 16 -bor $VER_PATCH -shl 8 -bor $VER_BUILD)) 26 | $Tokens.Add("VERSION_STRING", "{0}.{1}.{2}.{3}" -f ($VER_MAJOR,$VER_MINOR,$VER_PATCH,$VER_BUILD)) 27 | $Tokens.Add("BUILD_DATE", (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")) 28 | 29 | $Tokens.Add("PROJECT_NAME", $PROJECT_NAME) 30 | $Tokens.Add("CLIENT_NAME", $CLIENT_NAME) 31 | $Tokens.Add("SERVER_NAME", $SERVER_NAME) 32 | $Tokens.Add("APP_GUI_NAME", $APP_GUI_NAME) 33 | $Tokens.Add("PROJECT_COPY", $PROJECT_COPY) 34 | $Tokens.Add("PROJECT_URL", $PROJECT_URL) 35 | $Tokens.Add("PROJECT_DESC", $PROJECT_DESC) 36 | $Tokens.Add("PROJECT_LIC", $PROJECT_LIC) 37 | 38 | $Tokens.Add("AUTOGEN_MSG", "THIS FILE IS GENERATED BY A SCRIPT, CHANGES WILL NOT PERSIST. EDIT THE CORRESPONDING .in TEMPLATE FILE INSTEAD.") 39 | 40 | Merge-Tokens -InputFile $SrcPath\include\wasim_version.in -OutputFile $SrcPath\include\wasim_version.h -Tokens $Tokens -NoWarning 41 | Merge-Tokens -InputFile $SrcPath\WASimClient_CLI\AssemblyInfo.cpp.in -OutputFile $SrcPath\WASimClient_CLI\AssemblyInfo.cpp -Tokens $Tokens -NoWarning 42 | Merge-Tokens -InputFile $DocPath\version.Doxyfile.in -OutputFile $DocPath\version.Doxyfile -Tokens $Tokens -NoWarning 43 | $path = "${SrcPath}\WASimModule\WASimModuleProject\WASimCommander-Module\PackageDefinitions\wasimcommander-module.xml" 44 | Merge-Tokens -InputFile "${path}.in" -OutputFile $path -Tokens $Tokens -NoWarning 45 | 46 | } 47 | -------------------------------------------------------------------------------- /build/Merge-Tokens.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | 3 | .SYNOPSIS 4 | Replace tokens in a file with values. Originally from https://gist.github.com/niclaslindstedt/8425dbc5db81b779f3f46659f7232f91 5 | 6 | .DESCRIPTION 7 | Finds tokens in a given file and replace them with values. It is best used to replace configuration values in a release pipeline. 8 | 9 | .PARAMETER InputFile 10 | The file containing the tokens. 11 | 12 | .PARAMETER OutputFile 13 | The output file -- if you leave this empty, the input file will be replaced. 14 | 15 | .PARAMETER Tokens 16 | A hashtable containing the tokens and the value that should replace them. 17 | 18 | .PARAMETER TokenFile 19 | Read tokens as Key=Value pairs from given file. This adds to any tokens specified in Tokens parameter. 20 | 21 | .PARAMETER StartTokenPattern 22 | The start of the token, e.g. "{{". 23 | 24 | .PARAMETER EndTokenPattern 25 | The end of the token, e.g. "}}". 26 | 27 | .PARAMETER NullPattern 28 | The pattern that is used to signify $null. The reason for using this is that 29 | you cannot set an environment variable to null, so instead, set the environment 30 | variable to this pattern, and this script will replace the token with an empty string. 31 | 32 | .PARAMETER NoWarning 33 | If this is used, the script will not warn about tokens that cannot be found in the 34 | input file. This is useful when using environment variables to replace tokens since 35 | there will be a lot of warnings that aren't really warnings. 36 | 37 | .EXAMPLE 38 | config.template.json: 39 | { 40 | "url": "{{URL}}", 41 | "username": "{{USERNAME}}", 42 | "password": "{{PASSWORD}}" 43 | } 44 | 45 | Merge-Tokens ` 46 | -InputFile config.template.json ` 47 | -OutputFile config.json ` 48 | -Tokens @{URL="http://localhost:8080";USERNAME="admin";PASSWORD="Test123"} ` 49 | -StartTokenPattern "{{" ` 50 | -EndTokenPattern "}}" 51 | 52 | config.json (result): 53 | { 54 | "url": "http://localhost:8080", 55 | "username": "admin", 56 | "password": "Test123" 57 | } 58 | 59 | #> 60 | 61 | $PSDefaultParameterValues = @{ 'Out-File:encoding' = 'ASCII' } 62 | 63 | function Merge-Tokens { 64 | [CmdletBinding()] 65 | param( 66 | [string]$InputFile, 67 | [string]$OutputFile = $null, 68 | [string]$TokenFile = $null, 69 | [Hashtable]$Tokens = $null, 70 | [string]$StartTokenPattern = "@", 71 | [string]$EndTokenPattern = "@", 72 | [string]$NullPattern = ":::NULL:::", 73 | [switch]$NoWarning 74 | ) 75 | 76 | function GetTokenCount($line) { 77 | ($line | Select-String -Pattern "$($StartTokenPattern).+?$($EndTokenPattern)" -AllMatches).Matches.Count 78 | } 79 | 80 | # Check that input exists 81 | if (-not(Test-Path -Path $InputFile)) { 82 | Write-Warning "Input file not found: $InputFile" 83 | Exit 1 84 | } 85 | 86 | $TmpFile = [System.IO.Path]::GetTempFileName() 87 | 88 | # If the OutputFile is null, we will write to a temporary file 89 | if ([string]::IsNullOrWhiteSpace($OutputFile)) { 90 | Write-Verbose "OutputFile was omitted. Replacing InputFile." 91 | $OutputFile = $InputFile 92 | } 93 | 94 | # Empty OutputFile if it already exists 95 | if (Test-Path -Path $OutputFile) { 96 | #Write-Verbose "Clearing file $OutputFile" 97 | #Clear-Content -Encoding UTF8 -Path $OutputFile 98 | Remove-Item $OutputFile 99 | } 100 | 101 | if (![string]::IsNullOrWhiteSpace($TokenFile)) { 102 | (Get-Content $TokenFile) | ForEach-Object { 103 | $line = $_ 104 | Write-Verbose "Found $line" 105 | $kvp = $line -split '=' 106 | if ($kvp.Length -eq 2) { 107 | $Tokens.Add($kvp[0], $kvp[1]) 108 | Write-Verbose "Found $kvp[0] = $kvp[1]" 109 | } 110 | } 111 | } 112 | 113 | # Go through each line of the InputFile and replace the tokens with their values 114 | $totalTokens = 0 115 | $missedTokens = 0 116 | $usedTokens = New-Object -TypeName "System.Collections.ArrayList" 117 | 118 | #$sw = [System.IO.File]::AppendText($OutputFile) 119 | (Get-Content $InputFile) | ForEach-Object { 120 | $line = $_ 121 | $totalTokens += GetTokenCount($line) 122 | foreach ($key in $Tokens.Keys) { 123 | $token = "$($StartTokenPattern)$($key)$($EndTokenPattern)" 124 | $value = $Tokens.$key 125 | if ($line -match $token) { 126 | $usedTokens.Add($key) | Out-Null 127 | if ($value -eq $NullPattern) { 128 | $value = "" 129 | } 130 | Write-Verbose "Replacing $token with $value" 131 | $line = $line -replace "$token", "$value" 132 | } 133 | } 134 | $missedTokens += GetTokenCount($line) 135 | #$sw.WriteLine($line) 136 | $line | Out-File -Append -Encoding UTF8 -FilePath $TmpFile 137 | } 138 | 139 | # Remove UTF8 BOM 140 | Get-Content -Path $TmpFile | Out-File -FilePath $OutputFile 141 | 142 | # Write warning if there were tokens given in the Token parameter which were not replaced 143 | if (!$NoWarning -and $usedTokens.Count -ne $Tokens.Count) { 144 | $unusedTokens = New-Object -TypeName "System.Collections.ArrayList" 145 | foreach ($token in $Tokens.Keys) { 146 | if (!$usedTokens.Contains($token)) { 147 | $unusedTokens.Add($token) | Out-Null 148 | } 149 | } 150 | Write-Warning "The following tokens were not used: $($unusedTokens)" 151 | } 152 | 153 | # Write status message -- warn if there were tokens in the file that were not replaced 154 | $message = "Processed: $($InputFile) ($($totalTokens - $missedTokens) out of $totalTokens tokens replaced)" 155 | if ($missedTokens -gt 0) { 156 | Write-Warning $message 157 | } 158 | else { 159 | Write-Host $message 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /build/version.ps1: -------------------------------------------------------------------------------- 1 | 2 | $VER_MAJOR = 1 3 | $VER_MINOR = 3 4 | $VER_PATCH = 2 5 | $VER_BUILD = 0 6 | $VER_COMIT = 0 7 | $VER_NAME = "" 8 | 9 | $PROJECT_NAME = "WASimCommander" 10 | $CLIENT_NAME = "WASimClient" 11 | $SERVER_NAME = "WASimModule" 12 | $APP_GUI_NAME = "WASimUI" 13 | $PROJECT_COPY = "Copyright Maxim Paperno; All rights reserved." 14 | $PROJECT_URL = "https://github.com/mpaperno/WASimCommander" 15 | $PROJECT_DESC = "Remote access to the Microsoft Flight Simulator 2020 & 2024 Gauge API." 16 | $PROJECT_LIC = "$PROJECT_NAME API and $CLIENT_NAME licensed under LGPL v3 or GPL v3. $SERVER_NAME and all other code licensed under GPL v3. " + 17 | "Full terms are detailed in the README, LICENSE.GPL.txt, and LICENSE.LGPL.txt files which should accompany this distribution and are available at the project's URL." 18 | 19 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | html*/ 2 | xml*/ 3 | md*/ 4 | WASim?Logo*.* 5 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpaperno/WASimCommander/b156aba09128b7c899e27456bfbded5c46bfcbad/docs/.nojekyll -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | wasimcommander.max.paperno.us -------------------------------------------------------------------------------- /docs/Logo-square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpaperno/WASimCommander/b156aba09128b7c899e27456bfbded5c46bfcbad/docs/Logo-square.png -------------------------------------------------------------------------------- /docs/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpaperno/WASimCommander/b156aba09128b7c899e27456bfbded5c46bfcbad/docs/Logo.png -------------------------------------------------------------------------------- /docs/customdoxygen.css: -------------------------------------------------------------------------------- 1 | 2 | html { 3 | --content-maxwidth: auto; 4 | --side-nav-arrow-opacity: 0.6; 5 | /* --note-color: #969696; 6 | --note-color-dark: #634b03; 7 | --note-color-darker: #3d2e01; */ 8 | } 9 | 10 | /* html.dark-mode { 11 | --note-color: #969696; 12 | --note-color-dark: #634b03; 13 | --note-color-darker: #3d2e01; 14 | } */ 15 | 16 | #side-nav { 17 | padding-right: 6px !important; 18 | } 19 | 20 | .ui-resizable-e { 21 | width: 6px !important; 22 | } 23 | 24 | #titlearea { 25 | margin-right: 30px; 26 | } 27 | 28 | #projectlogo img 29 | { 30 | /* max-height: 56px; */ 31 | max-height: revert; 32 | margin-right: revert; 33 | } 34 | 35 | td#projectalign { 36 | vertical-align: bottom; 37 | } 38 | 39 | #projectname 40 | { 41 | /*font: bold 280% Tahoma, Arial,sans-serif;*/ 42 | /*margin: 0px;*/ 43 | padding: 2px 2px 0px 0px; 44 | /* font-variant: small-caps; */ 45 | } 46 | 47 | a.el, a.elRef { 48 | color: #009b00 !important; 49 | font-weight: normal; 50 | } 51 | 52 | a.el:visited, a.elRef:visited { 53 | color: #007800 !important; 54 | font-weight: normal; 55 | } 56 | 57 | html.dark-mode a.el, a.elRef { 58 | color: #06d206 !important; 59 | font-weight: normal; 60 | } 61 | 62 | html.dark-mode a.el:visited, html.dark-mode a.elRef:visited { 63 | color: #01b501 !important; 64 | font-weight: normal; 65 | } 66 | 67 | /*a[target=_blank] { 68 | color: #0059b3 !important; 69 | }*/ 70 | 71 | .navpath li.navelem a { 72 | font-weight: bold 73 | } 74 | div.fragment { 75 | padding: 5px; 76 | } 77 | 78 | /* Fix colors on "detail level" links */ 79 | .directory .levels span { 80 | color: var(--fragment-link); 81 | } 82 | 83 | /*div.line { 84 | padding: 2px 0; 85 | text-indent: 0; 86 | }*/ 87 | 88 | /*div.memproto { 89 | border-top-left-radius: 4px; 90 | background-color: #EBEBEE; 91 | }*/ 92 | 93 | /* smaller "Definition at line ..." */ 94 | p.definition { font-size: 11px !important; } 95 | 96 | /* hide large title block over each member details */ 97 | /*h2.memtitle { display: none; }*/ 98 | 99 | /* prettify detailed member titles */ 100 | /* table.memname tr { display: inline-table; } */ 101 | /* table.memname td { padding: 1px 0; } */ 102 | td.memname { font-weight: bold; } 103 | 104 | /* hide brief descriptions in member list, but not for parent class */ 105 | tr[class^="memdesc"] { display: none; } 106 | 107 | .github-corner svg { 108 | width: 63px; 109 | height: 63px; 110 | position: absolute; 111 | top: 10px; 112 | left: 300px; 113 | /* right: -20px; */ 114 | /* fill: var(--primary-light-color); */ 115 | color: var(--page-background-color); 116 | /* transform: scaleX(-1); */ 117 | z-index: 99; 118 | } 119 | .github-corner svg .first-stop { 120 | stop-color: #00B4FF; 121 | } 122 | .github-corner svg .last-stop { 123 | stop-color: #008AC6; 124 | } 125 | 126 | @media screen and (max-width: 1087px) { 127 | .github-corner svg { 128 | left: auto; 129 | right: 0; 130 | /* transform: revert; */ 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /docs/doxyawesome/doxygen-awesome-paragraph-link.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Doxygen Awesome 4 | https://github.com/jothepro/doxygen-awesome-css 5 | 6 | MIT License 7 | 8 | Copyright (c) 2022 - 2023 jothepro 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | 28 | */ 29 | 30 | class DoxygenAwesomeParagraphLink { 31 | // Icon from https://fonts.google.com/icons 32 | // Licensed under the Apache 2.0 license: 33 | // https://www.apache.org/licenses/LICENSE-2.0.html 34 | static icon = `` 35 | static title = "Permanent Link" 36 | static init() { 37 | $(function() { 38 | $(document).ready(function() { 39 | document.querySelectorAll(".contents a.anchor[id], .contents .groupheader > a[id]").forEach((node) => { 40 | let anchorlink = document.createElement("a") 41 | anchorlink.setAttribute("href", `#${node.getAttribute("id")}`) 42 | anchorlink.setAttribute("title", DoxygenAwesomeParagraphLink.title) 43 | anchorlink.classList.add("anchorlink") 44 | node.classList.add("anchor") 45 | anchorlink.innerHTML = DoxygenAwesomeParagraphLink.icon 46 | node.parentElement.appendChild(anchorlink) 47 | }) 48 | }) 49 | }) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /docs/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | $projectname: $title 10 | $title 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | $treeview 23 | $search 24 | $mathjax 25 | 26 | $extrastylesheet 27 | 28 | 29 | 33 | 34 | 35 | 36 | 37 |
38 | 39 | 40 | 41 | 42 |
43 | 44 | 45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 58 | 59 | 60 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
54 |
 $projectnumber 55 |
56 |
61 |
$projectbrief
62 |
$searchbox
$searchbox
80 |
81 | 82 | 83 | 84 | 85 | 86 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /docs/version.Doxyfile: -------------------------------------------------------------------------------- 1 | 2 | # Doxyfile 1.8.17 3 | # THIS FILE IS GENERATED BY A SCRIPT, CHANGES WILL NOT PERSIST. EDIT THE CORRESPONDING .in TEMPLATE FILE INSTEAD. 4 | 5 | PROJECT_NAME = "WASimCommander" 6 | PROJECT_NUMBER = v1.3.2.0 7 | PROJECT_BRIEF = "Remote access to the Microsoft Flight Simulator 2020 & 2024 Gauge API." 8 | -------------------------------------------------------------------------------- /docs/version.Doxyfile.in: -------------------------------------------------------------------------------- 1 | 2 | # Doxyfile 1.8.17 3 | # @AUTOGEN_MSG@ 4 | 5 | PROJECT_NAME = "@PROJECT_NAME@" 6 | PROJECT_NUMBER = v@VERSION_STRING@@VER_NAME@ 7 | PROJECT_BRIEF = "@PROJECT_DESC@" 8 | -------------------------------------------------------------------------------- /src/.editorconfig: -------------------------------------------------------------------------------- 1 | # overrides for top-level config 2 | [*.{c++,cc,cpp,cppm,cxx,cs,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}] 3 | indent_style=tab 4 | indent_size = 2 5 | insert_final_newline=true 6 | cpp_include_cleanup_excluded_files = MSFS_EventsEnum.h 7 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # WASimCommander 2 | ## "Just Read The Source" 3 | 4 | This directory has all the source code of the project. Contains the following components: 5 | 6 | | directory | description | 7 | | --------- | ----------- | 8 | | `include` | Shared C++ header files required to build or use any of the C++ API/libraries/code.
This is the only folder required to **use** the `WASimAPI` or C++ `WASimClient` library with your own code. | 9 | | `shared` | Code which is shared between client and module projects. Not part of public API. | 10 | | `Testing` | Test and example code in further sub-projects. | 11 | | `WASimClient` | The main WASim API Client implementation. | 12 | | `WASimClient_CLI` | The managed .NET "wrapper" of `WASimClient`, using C++/CLI. | 13 | | `WASimModule` | The MSFS 2020 WASM module implementation of the Server component. | 14 | | `WASimUI` | Full featured GUI for testing/exploring WASimCommander features. | 15 | 16 | -------------------------------------------------------------------------------- /src/Testing/CPP_BasicConsole/CPP_BasicConsole.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release-DLL 10 | x64 11 | 12 | 13 | Release 14 | x64 15 | 16 | 17 | 18 | 16.0 19 | Win32Proj 20 | {523abd54-4c1a-4f21-8977-5efa5821f71d} 21 | CPPBasicConsole 22 | 10.0 23 | 24 | 25 | 26 | Application 27 | true 28 | v142 29 | Unicode 30 | 31 | 32 | Application 33 | false 34 | v142 35 | true 36 | Unicode 37 | 38 | 39 | Application 40 | false 41 | v142 42 | true 43 | Unicode 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | true 65 | 66 | 67 | true 68 | 69 | 70 | 71 | Level3 72 | true 73 | WSMCMND_API_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE_DEBUG;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 74 | true 75 | stdcpp17 76 | stdc17 77 | 78 | 79 | Console 80 | true 81 | /ignore:4099 82 | 83 | 84 | 85 | 86 | Level3 87 | true 88 | true 89 | true 90 | WSMCMND_API_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE_DEBUG;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 91 | true 92 | stdcpp17 93 | stdc17 94 | None 95 | 96 | 97 | Console 98 | true 99 | true 100 | false 101 | /ignore:4099 102 | 103 | 104 | 105 | 106 | Level3 107 | true 108 | true 109 | true 110 | _CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE_DEBUG;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 111 | true 112 | stdcpp17 113 | stdc17 114 | None 115 | 116 | 117 | Console 118 | true 119 | true 120 | false 121 | /ignore:4099 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | {639093ff-fd94-4e89-92ac-c6fabe5df664} 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /src/Testing/CPP_BasicConsole/README.md: -------------------------------------------------------------------------------- 1 | 2 | # WASimCommander 3 | ## Basic Console Test for C++ 4 | 5 | This directory contains a simple console-based application for testing and demonstrating `WASimClient` API usage in a C++ program. 6 | 7 | It is set up for Visual Studio 2019, but can also be built with VS2022 (v143) with or w/out retargeting it. Other compilers have not been tested yet. 8 | 9 | This project depends on the `WASimClient` project. The resulting executable is standalone (if built with static linking to `WASimClient`). 10 | -------------------------------------------------------------------------------- /src/Testing/CS_BasicConsole/CS_BasicConsole.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | disable 6 | enable 7 | CS_BasicConsole.Program 8 | False 9 | x64 10 | False 11 | none 12 | x64 13 | Debug;Release-net5;Release-net6;Release-net7;Release-net8 14 | 1.1.0.0 15 | 1.1.0.0 16 | 17 | 18 | 19 | net8.0-windows 20 | embedded 21 | 22 | 23 | 24 | net5.0-windows 25 | embedded 26 | True 27 | 28 | 29 | 30 | net6.0-windows 31 | embedded 32 | True 33 | 34 | 35 | 36 | net7.0-windows 37 | embedded 38 | True 39 | 40 | 41 | 42 | net8.0-windows 43 | embedded 44 | True 45 | 46 | 47 | 48 | 49 | True 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/Testing/CS_BasicConsole/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | CS_BasicConsole 4 | $(SolutionDir)build\$(ProjectName)\$(Configuration)-$(Platform)\ 5 | $(SolutionDir)build\$(ProjectName)\obj\$(Configuration)-$(Platform)\ 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Testing/CS_BasicConsole/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "CS_BasicConsole": { 4 | "commandName": "Project", 5 | "nativeDebugging": true 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /src/Testing/CS_BasicConsole/README.md: -------------------------------------------------------------------------------- 1 | 2 | # WASimCommander 3 | ## Basic Console Test for C# 4 | 5 | This directory contains a simple console-based application for testing and demonstrating `WASimClient` API usage in managed C# code. 6 | 7 | It is set up with .NET v6 for Visual Studio 2022. This project depends on the `WASimClient_CLI` project (which in turn 8 | depends on `WASimClient` project). The built executable only needs the WASimCommander.WASimClient.dll assembly 9 | (produced by `WASimClient_CLI`) to be present. 10 | -------------------------------------------------------------------------------- /src/Testing/Py_BasicConsole/Py_BasicConsole.pyproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Debug 4 | 2.0 5 | c6d4303f-e717-4257-990b-2cae894898a0 6 | . 7 | Py_BasicConsole.py 8 | 9 | 10 | . 11 | . 12 | Py_BasicConsole 13 | Py_BasicConsole 14 | 15 | 16 | true 17 | false 18 | 19 | 20 | true 21 | false 22 | 23 | 24 | 25 | 26 | 27 | 28 | WASimClient_CLI 29 | {daf5b792-c4e6-4e54-9cbf-0a0335e80306} 30 | True 31 | 32 | 33 | 34 | 35 | True 36 | 37 | 38 | True 39 | 40 | 41 | True 42 | 43 | 44 | 45 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/Testing/Py_BasicConsole/README.md: -------------------------------------------------------------------------------- 1 | 2 | # WASimCommander 3 | ## Basic Console Test for Python 4 | 5 | This directory contains a simple console-based application for testing and demonstrating `WASimClient` API usage in Python, 6 | using [Python.NET](http://pythonnet.github.io/) to load the WASimClient_CLI .NET assembly. 7 | 8 | It is in fact almost an exact copy of the `CS_BasicConsole` version except modified for Python syntax. Pretty neat. 9 | 10 | Requires a 64-bit CPython, v3.8 or higher and Python.NET installed. Tested with `pythonnet 3.0.0rc3` which at the time of this writing requires 11 | `pip install pythonnet --pre`.
12 | (The current release 2.x version will probably work also but the error messages from that version are much harder to trace so I gave up on it.) 13 | 14 | The script needs the `WASimCommander.WASimClient.dll` assembly (and the `Ijwhost.dll` dependency) to be in Python's system search path. 15 | By default it's set up to look for the DLLs in the same folder as the script itself. To change the expected location, open the script 16 | and edit the path directives at the top (its commented). 17 | 18 | The `app.runtime.json` file is also required to set the correct .NET runtime, which is set to require v5.0.17 (WASimClient_CLI is currently built with .NET 5). 19 | You _may_ need to edit this file and modify the version number. 20 | 21 | Lastly, a `client_conf.ini` _should_ also be present in the folder, otherwise WASimClient will log a warning about not being able to find it. Though otherwise 22 | there's no problem with that, it'll just use built-in defaults instead. 23 | 24 | If all the above is set, then it's just a matter of running the script from a command line like you would any other Py script. 25 | -------------------------------------------------------------------------------- /src/Testing/Py_BasicConsole/app.runtime.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeOptions": { 3 | "tfm": "net8.0", 4 | "framework": { 5 | "name": "Microsoft.NETCore.App", 6 | "version": "8.0.0" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/WASimClient/LICENSE.LGPL.txt: -------------------------------------------------------------------------------- 1 | 2 | GNU LESSER GENERAL PUBLIC LICENSE 3 | Version 3, 29 June 2007 4 | 5 | Copyright (C) 2007 Free Software Foundation, Inc. 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | 10 | This version of the GNU Lesser General Public License incorporates 11 | the terms and conditions of version 3 of the GNU General Public 12 | License, supplemented by the additional permissions listed below. 13 | 14 | 0. Additional Definitions. 15 | 16 | As used herein, "this License" refers to version 3 of the GNU Lesser 17 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 18 | General Public License. 19 | 20 | "The Library" refers to a covered work governed by this License, 21 | other than an Application or a Combined Work as defined below. 22 | 23 | An "Application" is any work that makes use of an interface provided 24 | by the Library, but which is not otherwise based on the Library. 25 | Defining a subclass of a class defined by the Library is deemed a mode 26 | of using an interface provided by the Library. 27 | 28 | A "Combined Work" is a work produced by combining or linking an 29 | Application with the Library. The particular version of the Library 30 | with which the Combined Work was made is also called the "Linked 31 | Version". 32 | 33 | The "Minimal Corresponding Source" for a Combined Work means the 34 | Corresponding Source for the Combined Work, excluding any source code 35 | for portions of the Combined Work that, considered in isolation, are 36 | based on the Application, and not on the Linked Version. 37 | 38 | The "Corresponding Application Code" for a Combined Work means the 39 | object code and/or source code for the Application, including any data 40 | and utility programs needed for reproducing the Combined Work from the 41 | Application, but excluding the System Libraries of the Combined Work. 42 | 43 | 1. Exception to Section 3 of the GNU GPL. 44 | 45 | You may convey a covered work under sections 3 and 4 of this License 46 | without being bound by section 3 of the GNU GPL. 47 | 48 | 2. Conveying Modified Versions. 49 | 50 | If you modify a copy of the Library, and, in your modifications, a 51 | facility refers to a function or data to be supplied by an Application 52 | that uses the facility (other than as an argument passed when the 53 | facility is invoked), then you may convey a copy of the modified 54 | version: 55 | 56 | a) under this License, provided that you make a good faith effort to 57 | ensure that, in the event an Application does not supply the 58 | function or data, the facility still operates, and performs 59 | whatever part of its purpose remains meaningful, or 60 | 61 | b) under the GNU GPL, with none of the additional permissions of 62 | this License applicable to that copy. 63 | 64 | 3. Object Code Incorporating Material from Library Header Files. 65 | 66 | The object code form of an Application may incorporate material from 67 | a header file that is part of the Library. You may convey such object 68 | code under terms of your choice, provided that, if the incorporated 69 | material is not limited to numerical parameters, data structure 70 | layouts and accessors, or small macros, inline functions and templates 71 | (ten or fewer lines in length), you do both of the following: 72 | 73 | a) Give prominent notice with each copy of the object code that the 74 | Library is used in it and that the Library and its use are 75 | covered by this License. 76 | 77 | b) Accompany the object code with a copy of the GNU GPL and this license 78 | document. 79 | 80 | 4. Combined Works. 81 | 82 | You may convey a Combined Work under terms of your choice that, 83 | taken together, effectively do not restrict modification of the 84 | portions of the Library contained in the Combined Work and reverse 85 | engineering for debugging such modifications, if you also do each of 86 | the following: 87 | 88 | a) Give prominent notice with each copy of the Combined Work that 89 | the Library is used in it and that the Library and its use are 90 | covered by this License. 91 | 92 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 93 | document. 94 | 95 | c) For a Combined Work that displays copyright notices during 96 | execution, include the copyright notice for the Library among 97 | these notices, as well as a reference directing the user to the 98 | copies of the GNU GPL and this license document. 99 | 100 | d) Do one of the following: 101 | 102 | 0) Convey the Minimal Corresponding Source under the terms of this 103 | License, and the Corresponding Application Code in a form 104 | suitable for, and under terms that permit, the user to 105 | recombine or relink the Application with a modified version of 106 | the Linked Version to produce a modified Combined Work, in the 107 | manner specified by section 6 of the GNU GPL for conveying 108 | Corresponding Source. 109 | 110 | 1) Use a suitable shared library mechanism for linking with the 111 | Library. A suitable mechanism is one that (a) uses at run time 112 | a copy of the Library already present on the user's computer 113 | system, and (b) will operate properly with a modified version 114 | of the Library that is interface-compatible with the Linked 115 | Version. 116 | 117 | e) Provide Installation Information, but only if you would otherwise 118 | be required to provide such information under section 6 of the 119 | GNU GPL, and only to the extent that such information is 120 | necessary to install and execute a modified version of the 121 | Combined Work produced by recombining or relinking the 122 | Application with a modified version of the Linked Version. (If 123 | you use option 4d0, the Installation Information must accompany 124 | the Minimal Corresponding Source and Corresponding Application 125 | Code. If you use option 4d1, you must provide the Installation 126 | Information in the manner specified by section 6 of the GNU GPL 127 | for conveying Corresponding Source.) 128 | 129 | 5. Combined Libraries. 130 | 131 | You may place library facilities that are a work based on the 132 | Library side by side in a single library together with other library 133 | facilities that are not Applications and are not covered by this 134 | License, and convey such a combined library under terms of your 135 | choice, if you do both of the following: 136 | 137 | a) Accompany the combined library with a copy of the same work based 138 | on the Library, uncombined with any other library facilities, 139 | conveyed under the terms of this License. 140 | 141 | b) Give prominent notice with the combined library that part of it 142 | is a work based on the Library, and explaining where to find the 143 | accompanying uncombined form of the same work. 144 | 145 | 6. Revised Versions of the GNU Lesser General Public License. 146 | 147 | The Free Software Foundation may publish revised and/or new versions 148 | of the GNU Lesser General Public License from time to time. Such new 149 | versions will be similar in spirit to the present version, but may 150 | differ in detail to address new problems or concerns. 151 | 152 | Each version is given a distinguishing version number. If the 153 | Library as you received it specifies that a certain numbered version 154 | of the GNU Lesser General Public License "or any later version" 155 | applies to it, you have the option of following the terms and 156 | conditions either of that published version or of any later version 157 | published by the Free Software Foundation. If the Library as you 158 | received it does not specify a version number of the GNU Lesser 159 | General Public License, you may choose any version of the GNU Lesser 160 | General Public License ever published by the Free Software Foundation. 161 | 162 | If the Library as you received it specifies that a proxy can decide 163 | whether future versions of the GNU Lesser General Public License shall 164 | apply, that proxy's public statement of acceptance of any version is 165 | permanent authorization for you to choose that version for the 166 | Library. 167 | -------------------------------------------------------------------------------- /src/WASimClient/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | WASimCommander Project 3 | WASimClient - Client Implementation of WASim API 4 | 5 | COPYRIGHT: Maxim Paperno; All Rights Reserved. 6 | 7 | Dual licensed under the terms of either the GNU General Public License (**GPL**) 8 | or the GNU Lesser General Public License (**LGPL**), as published by the Free Software 9 | Foundation, either **version 3** of the Licenses, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Copies of the GNU GPL and LGPL are included with this project 17 | in the files named LICENSE.GPL.txt and LICENSE.LGPL.txt respectively, 18 | and are available at . 19 | 20 | Except as contained in this copyright notice, the names of the authors or 21 | their institutions shall not be used in advertising or otherwise to 22 | promote the sale, use, or other dealings in, any product using this 23 | Software, or any derivative of this Software, without prior written 24 | authorization from the authors. 25 | 26 | This project may also use 3rd-party Open Source software under the terms 27 | of their respective licenses. The copyright notice above does not apply 28 | to any 3rd-party components used within. 29 | -------------------------------------------------------------------------------- /src/WASimClient/README.md: -------------------------------------------------------------------------------- 1 | 2 | # WASimCommander 3 | ## WASimClient - C++ Implementation of The WASim API 4 | 5 | This directory contains the implementation of a Client-side library for all aspects of communication with the WASimCommander Server component (`WASimModule`). 6 | 7 | It is designed to be integrated as either a static or dynamic library into other software. 8 | To encourage adaptation, it is dual licensed under the terms of the GPL (dynamic or static linking) 9 | or LGPL (dynamic linking). 10 | 11 | See corresponding LICENSE.txt for licensing details. 12 | 13 | ### Building Note 14 | 15 | When building with MSVC against the pre-built version of this library, either static or dynamic, be sure build with `/MD` or `/MDd` (debug) options. 16 | That's the _Runtime Library_ property, "Multi-threaded DLL" setting (or "Multi-threaded Debug DLL" for debug builds). And don't mix up the debug 17 | vs. release difference, or there will be untraceable crashing and burning. These should be the default settings on a new project, but you never know. 18 | -------------------------------------------------------------------------------- /src/WASimClient/client_conf.ini: -------------------------------------------------------------------------------- 1 | [logging] 2 | ; Log file path is relative to the current working directory (not necessarily executable's directory); or can be absolute. 3 | logFilepath = .\ 4 | ; Logging level names are: None, Critical, Error, Warning, Info, Debug, Trace 5 | fileLogLevel = Info 6 | consoleLogLevel = Info 7 | 8 | [network] 9 | ; SimConnect.cfg index or -1 for default local connection 10 | networkConfigId = -1 11 | ; Default timeout for network requests to server, in milliseconds. 12 | networkTimeout = 1000 13 | ; Enable SimConnect request tracking for detailed exception messages by setting to a positive integer; Disable by setting to 0 (zero). 14 | requestTrackingMaxRecords = 200 15 | -------------------------------------------------------------------------------- /src/WASimClient/dllmain.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of either the GNU General Public License (GPL) 8 | or the GNU Lesser General Public License (LGPL), as published by the Free Software 9 | Foundation, either version 3 of the Licenses, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Copies of the GNU GPL and LGPL are included with this project 17 | and are available at . 18 | */ 19 | 20 | // dllmain.cpp : Defines the entry point for the DLL application. 21 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 22 | #include 23 | 24 | BOOL APIENTRY DllMain( HMODULE hModule, 25 | DWORD ul_reason_for_call, 26 | LPVOID lpReserved 27 | ) 28 | { 29 | switch (ul_reason_for_call) 30 | { 31 | case DLL_PROCESS_ATTACH: 32 | case DLL_THREAD_ATTACH: 33 | case DLL_THREAD_DETACH: 34 | case DLL_PROCESS_DETACH: 35 | break; 36 | } 37 | return TRUE; 38 | } 39 | 40 | -------------------------------------------------------------------------------- /src/WASimClient_CLI/AssemblyInfo.cpp: -------------------------------------------------------------------------------- 1 | 2 | // THIS FILE IS GENERATED BY A SCRIPT, CHANGES WILL NOT PERSIST. EDIT THE CORRESPONDING .in TEMPLATE FILE INSTEAD. 3 | 4 | using namespace System; 5 | using namespace System::Reflection; 6 | using namespace System::Runtime::CompilerServices; 7 | using namespace System::Runtime::InteropServices; 8 | using namespace System::Security::Permissions; 9 | 10 | #ifdef _DEBUG 11 | [assembly:AssemblyTitleAttribute(L"WASimClient [DBG]")]; 12 | [assembly:AssemblyConfigurationAttribute("Debug")] 13 | #else 14 | [assembly:AssemblyTitleAttribute(L"WASimClient")]; 15 | [assembly:AssemblyConfigurationAttribute("Release")] 16 | #endif 17 | 18 | [assembly:AssemblyDescriptionAttribute(L"CLI Wrapper for WASimCommander's general API and the WASimClient class.")]; 19 | [assembly:AssemblyCompanyAttribute(L"Maxim Paperno")]; 20 | [assembly:AssemblyProductAttribute(L"WASimCommander - Remote access to the Microsoft Flight Simulator 2020 & 2024 Gauge API.")]; 21 | [assembly:AssemblyCopyrightAttribute(L"Copyright Maxim Paperno; All rights reserved.")]; 22 | [assembly:AssemblyTrademarkAttribute(L"")]; 23 | [assembly:AssemblyCultureAttribute(L"")]; 24 | 25 | [assembly:AssemblyVersionAttribute(L"1.3.2.0")]; 26 | [assembly:AssemblyFileVersionAttribute("1.3.2.0")]; 27 | [assembly:AssemblyInformationalVersionAttribute("1.3.2.0")]; 28 | 29 | [assembly:ComVisible(false)]; 30 | -------------------------------------------------------------------------------- /src/WASimClient_CLI/AssemblyInfo.cpp.in: -------------------------------------------------------------------------------- 1 | 2 | // @AUTOGEN_MSG@ 3 | 4 | using namespace System; 5 | using namespace System::Reflection; 6 | using namespace System::Runtime::CompilerServices; 7 | using namespace System::Runtime::InteropServices; 8 | using namespace System::Security::Permissions; 9 | 10 | #ifdef _DEBUG 11 | [assembly:AssemblyTitleAttribute(L"@CLIENT_NAME@ [DBG]")]; 12 | [assembly:AssemblyConfigurationAttribute("Debug")] 13 | #else 14 | [assembly:AssemblyTitleAttribute(L"@CLIENT_NAME@")]; 15 | [assembly:AssemblyConfigurationAttribute("Release")] 16 | #endif 17 | 18 | [assembly:AssemblyDescriptionAttribute(L"CLI Wrapper for @PROJECT_NAME@'s general API and the @CLIENT_NAME@ class.")]; 19 | [assembly:AssemblyCompanyAttribute(L"Maxim Paperno")]; 20 | [assembly:AssemblyProductAttribute(L"@PROJECT_NAME@ - @PROJECT_DESC@")]; 21 | [assembly:AssemblyCopyrightAttribute(L"@PROJECT_COPY@")]; 22 | [assembly:AssemblyTrademarkAttribute(L"")]; 23 | [assembly:AssemblyCultureAttribute(L"")]; 24 | 25 | [assembly:AssemblyVersionAttribute(L"@VERSION_STRING@")]; 26 | [assembly:AssemblyFileVersionAttribute("@VERSION_STRING@")]; 27 | [assembly:AssemblyInformationalVersionAttribute("@VERSION_STRING@@VER_NAME@")]; 28 | 29 | [assembly:ComVisible(false)]; 30 | -------------------------------------------------------------------------------- /src/WASimClient_CLI/Enums.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of either the GNU General Public License (GPL) 8 | or the GNU Lesser General Public License (LGPL), as published by the Free Software 9 | Foundation, either version 3 of the Licenses, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Copies of the GNU GPL and LGPL are included with this project 17 | and are available at . 18 | */ 19 | 20 | #pragma once 21 | 22 | #ifdef min 23 | #undef min 24 | #undef max 25 | #endif 26 | #include 27 | 28 | #ifdef WSMCMND_ENUM_EXPORT 29 | #undef WSMCMND_ENUM_EXPORT 30 | #undef WSMCMND_ENUM_NAMESPACE 31 | #endif 32 | 33 | //#include "client/WASimClient.h" 34 | #define WSMCMND_ENUM_EXPORT public 35 | #define WSMCMND_ENUM_NAMESPACE WASimCommander::CLI::Enums 36 | #include "enums_impl.h" 37 | #include "client/enums_impl.h" 38 | 39 | /// WASimCommander::CLI::Enums namespace. C++/CLI specific definitions only. 40 | /// See documentation for `WASimCommander::Enums` and `WASimCommander::Client` namespaces for main API and Client enum classes respectively. 41 | namespace WASimCommander::CLI::Enums 42 | { 43 | 44 | /// Custom "+" operator for strong C++ enum types to cast to underlying type. 45 | template ::value, bool> = true> 46 | constexpr auto operator+(T e) noexcept { return static_cast>(e); } 47 | 48 | /// Method return status values; HRESULT "alias" 49 | public enum class HR 50 | { 51 | OK = S_OK, ///< Success status. 52 | FAIL = E_FAIL, ///< General error status, 53 | INVALIDARG = E_INVALIDARG, ///< Invalid method argument. 54 | NOT_CONNECTED = int(/*ERROR_NOT_CONNECTED*/ 2250L | (/*FACILITY_WIN32*/ 7 << 16) | 0x80000000), ///< Error result: server not connected. 55 | TIMEOUT = int(/*ERROR_TIMEOUT*/ 1460L | (/*FACILITY_WIN32*/ 7 << 16) | 0x80000000), ///< Error result: timeout communicating with server. 56 | }; 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/WASimClient_CLI/LICENSE.LGPL.txt: -------------------------------------------------------------------------------- 1 | 2 | GNU LESSER GENERAL PUBLIC LICENSE 3 | Version 3, 29 June 2007 4 | 5 | Copyright (C) 2007 Free Software Foundation, Inc. 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | 10 | This version of the GNU Lesser General Public License incorporates 11 | the terms and conditions of version 3 of the GNU General Public 12 | License, supplemented by the additional permissions listed below. 13 | 14 | 0. Additional Definitions. 15 | 16 | As used herein, "this License" refers to version 3 of the GNU Lesser 17 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 18 | General Public License. 19 | 20 | "The Library" refers to a covered work governed by this License, 21 | other than an Application or a Combined Work as defined below. 22 | 23 | An "Application" is any work that makes use of an interface provided 24 | by the Library, but which is not otherwise based on the Library. 25 | Defining a subclass of a class defined by the Library is deemed a mode 26 | of using an interface provided by the Library. 27 | 28 | A "Combined Work" is a work produced by combining or linking an 29 | Application with the Library. The particular version of the Library 30 | with which the Combined Work was made is also called the "Linked 31 | Version". 32 | 33 | The "Minimal Corresponding Source" for a Combined Work means the 34 | Corresponding Source for the Combined Work, excluding any source code 35 | for portions of the Combined Work that, considered in isolation, are 36 | based on the Application, and not on the Linked Version. 37 | 38 | The "Corresponding Application Code" for a Combined Work means the 39 | object code and/or source code for the Application, including any data 40 | and utility programs needed for reproducing the Combined Work from the 41 | Application, but excluding the System Libraries of the Combined Work. 42 | 43 | 1. Exception to Section 3 of the GNU GPL. 44 | 45 | You may convey a covered work under sections 3 and 4 of this License 46 | without being bound by section 3 of the GNU GPL. 47 | 48 | 2. Conveying Modified Versions. 49 | 50 | If you modify a copy of the Library, and, in your modifications, a 51 | facility refers to a function or data to be supplied by an Application 52 | that uses the facility (other than as an argument passed when the 53 | facility is invoked), then you may convey a copy of the modified 54 | version: 55 | 56 | a) under this License, provided that you make a good faith effort to 57 | ensure that, in the event an Application does not supply the 58 | function or data, the facility still operates, and performs 59 | whatever part of its purpose remains meaningful, or 60 | 61 | b) under the GNU GPL, with none of the additional permissions of 62 | this License applicable to that copy. 63 | 64 | 3. Object Code Incorporating Material from Library Header Files. 65 | 66 | The object code form of an Application may incorporate material from 67 | a header file that is part of the Library. You may convey such object 68 | code under terms of your choice, provided that, if the incorporated 69 | material is not limited to numerical parameters, data structure 70 | layouts and accessors, or small macros, inline functions and templates 71 | (ten or fewer lines in length), you do both of the following: 72 | 73 | a) Give prominent notice with each copy of the object code that the 74 | Library is used in it and that the Library and its use are 75 | covered by this License. 76 | 77 | b) Accompany the object code with a copy of the GNU GPL and this license 78 | document. 79 | 80 | 4. Combined Works. 81 | 82 | You may convey a Combined Work under terms of your choice that, 83 | taken together, effectively do not restrict modification of the 84 | portions of the Library contained in the Combined Work and reverse 85 | engineering for debugging such modifications, if you also do each of 86 | the following: 87 | 88 | a) Give prominent notice with each copy of the Combined Work that 89 | the Library is used in it and that the Library and its use are 90 | covered by this License. 91 | 92 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 93 | document. 94 | 95 | c) For a Combined Work that displays copyright notices during 96 | execution, include the copyright notice for the Library among 97 | these notices, as well as a reference directing the user to the 98 | copies of the GNU GPL and this license document. 99 | 100 | d) Do one of the following: 101 | 102 | 0) Convey the Minimal Corresponding Source under the terms of this 103 | License, and the Corresponding Application Code in a form 104 | suitable for, and under terms that permit, the user to 105 | recombine or relink the Application with a modified version of 106 | the Linked Version to produce a modified Combined Work, in the 107 | manner specified by section 6 of the GNU GPL for conveying 108 | Corresponding Source. 109 | 110 | 1) Use a suitable shared library mechanism for linking with the 111 | Library. A suitable mechanism is one that (a) uses at run time 112 | a copy of the Library already present on the user's computer 113 | system, and (b) will operate properly with a modified version 114 | of the Library that is interface-compatible with the Linked 115 | Version. 116 | 117 | e) Provide Installation Information, but only if you would otherwise 118 | be required to provide such information under section 6 of the 119 | GNU GPL, and only to the extent that such information is 120 | necessary to install and execute a modified version of the 121 | Combined Work produced by recombining or relinking the 122 | Application with a modified version of the Linked Version. (If 123 | you use option 4d0, the Installation Information must accompany 124 | the Minimal Corresponding Source and Corresponding Application 125 | Code. If you use option 4d1, you must provide the Installation 126 | Information in the manner specified by section 6 of the GNU GPL 127 | for conveying Corresponding Source.) 128 | 129 | 5. Combined Libraries. 130 | 131 | You may place library facilities that are a work based on the 132 | Library side by side in a single library together with other library 133 | facilities that are not Applications and are not covered by this 134 | License, and convey such a combined library under terms of your 135 | choice, if you do both of the following: 136 | 137 | a) Accompany the combined library with a copy of the same work based 138 | on the Library, uncombined with any other library facilities, 139 | conveyed under the terms of this License. 140 | 141 | b) Give prominent notice with the combined library that part of it 142 | is a work based on the Library, and explaining where to find the 143 | accompanying uncombined form of the same work. 144 | 145 | 6. Revised Versions of the GNU Lesser General Public License. 146 | 147 | The Free Software Foundation may publish revised and/or new versions 148 | of the GNU Lesser General Public License from time to time. Such new 149 | versions will be similar in spirit to the present version, but may 150 | differ in detail to address new problems or concerns. 151 | 152 | Each version is given a distinguishing version number. If the 153 | Library as you received it specifies that a certain numbered version 154 | of the GNU Lesser General Public License "or any later version" 155 | applies to it, you have the option of following the terms and 156 | conditions either of that published version or of any later version 157 | published by the Free Software Foundation. If the Library as you 158 | received it does not specify a version number of the GNU Lesser 159 | General Public License, you may choose any version of the GNU Lesser 160 | General Public License ever published by the Free Software Foundation. 161 | 162 | If the Library as you received it specifies that a proxy can decide 163 | whether future versions of the GNU Lesser General Public License shall 164 | apply, that proxy's public statement of acceptance of any version is 165 | permanent authorization for you to choose that version for the 166 | Library. 167 | -------------------------------------------------------------------------------- /src/WASimClient_CLI/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | WASimCommander Project 3 | WASimClient_CLI - C++/CLI Wrapper of WASimCommander Components 4 | 5 | COPYRIGHT: Maxim Paperno; All Rights Reserved. 6 | 7 | Dual licensed under the terms of either the GNU General Public License (**GPL**) 8 | or the GNU Lesser General Public License (**LGPL**), as published by the Free Software 9 | Foundation, either **version 3** of the Licenses, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Copies of the GNU GPL and LGPL are included with this project 17 | in the files named LICENSE.GPL.txt and LICENSE.LGPL.txt respectively, 18 | and are available at . 19 | 20 | Except as contained in this copyright notice, the names of the authors or 21 | their institutions shall not be used in advertising or otherwise to 22 | promote the sale, use, or other dealings in, any product using this 23 | Software, or any derivative of this Software, without prior written 24 | authorization from the authors. 25 | 26 | This project may also use 3rd-party Open Source software under the terms 27 | of their respective licenses. The copyright notice above does not apply 28 | to any 3rd-party components used within. 29 | -------------------------------------------------------------------------------- /src/WASimClient_CLI/README.md: -------------------------------------------------------------------------------- 1 | 2 | # WASimCommander 3 | ## WASimClient_CLI - C++/CLI Wrapper of WASimCommander Components 4 | 5 | This directory contains the C++/CLI "wrapper" of the `WASimClient` C++ library, used for all 6 | aspects of communication with the WASimCommander Server component (`WASimModule`). 7 | 8 | This code produces a .NET Core or .NET Framework managed assembly DLL which can be used with pure C# projects, 9 | and possibly other languages which can consume .NET assemblies. 10 | 11 | It is designed to be integrated as a dynamic library into other software. 12 | To encourage adaptation, it is dual licensed under the terms of the GPL or LGPL (see LICENSE.txt for details). 13 | -------------------------------------------------------------------------------- /src/WASimClient_CLI/WASimCommander_CLI.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of either the GNU General Public License (GPL) 8 | or the GNU Lesser General Public License (LGPL), as published by the Free Software 9 | Foundation, either version 3 of the Licenses, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Copies of the GNU GPL and LGPL are included with this project 17 | and are available at . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "./Enums.h" 23 | #include "./Structs.h" 24 | 25 | using namespace System; 26 | 27 | /// WASimCommander::CLI namespace. 28 | /// Container for implementation of the C++ `WASimCommander` API and `WASimClient` as a C++/CLI .NET "wrapper." 29 | /// The primary documentation is for the C++ version equivalents. Documentation for everything in the CLI namespace 30 | /// focuses primarily on any (non-obvious) differences from the C++ version. 31 | namespace WASimCommander::CLI 32 | { 33 | /// Predefined value types 34 | /// Using these constants for the `WASimCommander::CLI::Structs::DataRequest::valueSize` property will allow delta epsilon comparisons. 35 | public value struct ValueTypes { 36 | literal UInt32 DATA_TYPE_INT8 = DATA_TYPE_INT8; ///< 8-bit integer number (signed or unsigned) 37 | literal UInt32 DATA_TYPE_INT16 = DATA_TYPE_INT16; ///< 16-bit integer number (signed or unsigned) 38 | literal UInt32 DATA_TYPE_INT32 = DATA_TYPE_INT32; ///< 32-bit integer number (signed or unsigned) 39 | literal UInt32 DATA_TYPE_INT64 = DATA_TYPE_INT64; ///< 64-bit integer number (signed or unsigned) 40 | literal UInt32 DATA_TYPE_FLOAT = DATA_TYPE_FLOAT; ///< 32-bit floating-point number 41 | literal UInt32 DATA_TYPE_DOUBLE = DATA_TYPE_DOUBLE; ///< 64-bit floating-point number 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /src/WASimClient_CLI/deps.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/WASimModule/README.md: -------------------------------------------------------------------------------- 1 | 2 | # WASimCommander 3 | ## WASimModule - MSFS WASM Module Server Component 4 | 5 | This directory contains the implementation of the WASM module code and the MSFS project used to build the final distribution package. 6 | 7 | The built version of the module should be placed into the MSFS2020 _Community_ folder. The folder `wasimcommander-module` and all its contents 8 | can simply be dragged and dropped into place. 9 | -------------------------------------------------------------------------------- /src/WASimModule/WASimModule.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | MSFS 7 | 8 | 9 | Release 10 | MSFS 11 | 12 | 13 | 14 | 16.0 15 | {A5468B35-BBBD-4C55-97ED-81BFE343B0E4} 16 | WASimCommander 17 | 10.0 18 | WASimModule 19 | 20 | 21 | 22 | Application 23 | true 24 | MSFS 25 | MultiByte 26 | 27 | 28 | Application 29 | false 30 | MSFS 31 | true 32 | MultiByte 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | $(SolutionDir)build\$(ProjectName)\$(Configuration)\ 50 | $(SolutionDir)build\$(ProjectName)\obj\$(Configuration)\ 51 | 52 | 53 | true 54 | .wasm 55 | $(SolutionDir)\shared;$(MSFS_IncludePath);$(IncludePath) 56 | true 57 | 58 | 59 | false 60 | .wasm 61 | $(SolutionDir)\shared;$(MSFS_IncludePath);$(IncludePath) 62 | 63 | 64 | 65 | Level3 66 | Disabled 67 | true 68 | _DEBUG;__wasi__;_MSFS_WASM;_STRING_H_CPLUSPLUS_98_CONFORMANCE_;_WCHAR_H_CPLUSPLUS_98_CONFORMANCE_;_LIBCPP_NO_EXCEPTIONS;_LIBCPP_HAS_NO_THREADS;%(PreprocessorDefinitions) 69 | true 70 | 71 | 72 | false 73 | false 74 | ProgramDatabase 75 | 76 | stdcpp17 77 | -Wno-ignored-attributes -Wno-macro-redefined -Wno-unused-function -Wno-c++17-extensions /Zc:__cplusplus %(AdditionalOptions) 78 | stdc17 79 | 80 | 81 | Windows 82 | true 83 | true 84 | 85 | 86 | copy /Y "$(OutDir)*.*" "$(ProjectDir)\WASimModuleProject\WASimCommander-Module\PackageSources\WASimModule" 87 | 88 | 89 | 90 | 91 | Level3 92 | MaxSpeed 93 | true 94 | true 95 | true 96 | NDEBUG;__wasi__;_MSFS_WASM;_STRING_H_CPLUSPLUS_98_CONFORMANCE_;_WCHAR_H_CPLUSPLUS_98_CONFORMANCE_;_LIBCPP_NO_EXCEPTIONS;_LIBCPP_HAS_NO_THREADS;%(PreprocessorDefinitions) 97 | true 98 | 99 | 100 | false 101 | false 102 | 103 | stdcpp17 104 | -Wno-ignored-attributes -Wno-macro-redefined -Wno-unused-function -Wno-c++17-extensions /Zc:__cplusplus /clang:-O3 %(AdditionalOptions) 105 | stdc17 106 | 107 | 108 | Windows 109 | true 110 | true 111 | false 112 | true 113 | 114 | 115 | copy /Y "$(OutDir)*.*" "$(ProjectDir)\WASimModuleProject\WASimCommander-Module\PackageSources\WASimModule" 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | true 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /src/WASimModule/WASimModuleProject/WASimCommander-Module/.gitignore: -------------------------------------------------------------------------------- 1 | _PackageInt/ 2 | Packages/ 3 | PackagesMetadata/ 4 | PackageSources/WASimModule/*.wasm 5 | PackageSources/WASimModule/*.ini 6 | -------------------------------------------------------------------------------- /src/WASimModule/WASimModuleProject/WASimCommander-Module/PackageDefinitions/wasimcommander-module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MISC 5 | WASimCommander WASM Module 6 | 7 | Copyright Maxim Paperno; All rights reserved. 8 | 9 | 10 | false 11 | false 12 | 13 | 14 | 15 | ContentInfo 16 | 17 | false 18 | 19 | PackageDefinitions\wasimcommander-module\ContentInfo\ 20 | ContentInfo\wasimcommander-module\ 21 | 22 | 23 | Copy 24 | 25 | false 26 | 27 | PackageSources\WASimModule\ 28 | modules\ 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/WASimModule/WASimModuleProject/WASimCommander-Module/PackageDefinitions/wasimcommander-module.xml.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MISC 5 | @PROJECT_NAME@ WASM Module 6 | 7 | @PROJECT_COPY@ 8 | 9 | 10 | false 11 | false 12 | 13 | 14 | 15 | ContentInfo 16 | 17 | false 18 | 19 | PackageDefinitions\wasimcommander-module\ContentInfo\ 20 | ContentInfo\wasimcommander-module\ 21 | 22 | 23 | Copy 24 | 25 | false 26 | 27 | PackageSources\@SERVER_NAME@\ 28 | modules\ 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/WASimModule/WASimModuleProject/WASimCommander-Module/PackageDefinitions/wasimcommander-module/ContentInfo/Thumbnail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpaperno/WASimCommander/b156aba09128b7c899e27456bfbded5c46bfcbad/src/WASimModule/WASimModuleProject/WASimCommander-Module/PackageDefinitions/wasimcommander-module/ContentInfo/Thumbnail.jpg -------------------------------------------------------------------------------- /src/WASimModule/WASimModuleProject/WASimCommander-Module/PackageSources/WASimModule/.gitinclude: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpaperno/WASimCommander/b156aba09128b7c899e27456bfbded5c46bfcbad/src/WASimModule/WASimModuleProject/WASimCommander-Module/PackageSources/WASimModule/.gitinclude -------------------------------------------------------------------------------- /src/WASimModule/WASimModuleProject/WASimCommander-Module/WASimCommander-Module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | . 4 | _PackageInt 5 | _PublishingGroupInt 6 | 7 | PackageDefinitions\wasimcommander-module.xml 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/WASimModule/server_conf.ini: -------------------------------------------------------------------------------- 1 | [logging] 2 | ; Logging level names are: None, Critical, Error, Warning, Info, Debug, Trace 3 | fileLogLevel = Debug 4 | consoleLogLevel = Info 5 | 6 | [network] 7 | ; Enable SimConnect request tracking for detailed exception messages by setting to a positive integer; Disable by setting to 0 (zero). 8 | requestTrackingMaxRecords = 25 9 | -------------------------------------------------------------------------------- /src/WASimUI/DocImports.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of the GNU General Public License (GPL) 8 | as published by the Free Software Foundation, either version 3 of the Licenses, 9 | or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | A copy of the GNU GPL is included with this project 17 | and is also available at . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "Widgets.h" 32 | 33 | namespace WASimUiNS { 34 | namespace DocImports 35 | { 36 | Q_NAMESPACE 37 | 38 | const QString DB_NAME = QStringLiteral("MSFS_SDK_Doc_Import"); 39 | 40 | enum RecordType : quint8 { Unknown, SimVars, KeyEvents, SimVarUnits }; 41 | Q_ENUM_NS(RecordType) 42 | 43 | static const QVector RecordTypeNames { 44 | "Unknown", "Simulator Variables", "Key Events", "Variable Units" 45 | }; 46 | static QString recordTypeName(RecordType type) { 47 | return RecordTypeNames.value(type, RecordTypeNames[RecordType::Unknown]); 48 | } 49 | 50 | static bool createConnection() 51 | { 52 | QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", DB_NAME); 53 | db.setDatabaseName(DB_NAME + ".sqlite3"); 54 | db.setConnectOptions("QSQLITE_OPEN_READONLY;QSQLITE_ENABLE_SHARED_CACHE;QSQLITE_ENABLE_REGEXP=30"); 55 | if (db.open()) 56 | return true; 57 | qDebug() << "Failed to open database" << DB_NAME << ".sqlite3 with:" << db.lastError(); 58 | db = QSqlDatabase(); 59 | QSqlDatabase::removeDatabase(DB_NAME); 60 | return false; 61 | } 62 | 63 | static QSqlDatabase getConnection(bool open = true) 64 | { 65 | if (!QSqlDatabase::contains(DB_NAME)) { 66 | if (!createConnection()) 67 | return QSqlDatabase::database(); 68 | } 69 | return QSqlDatabase::database(DB_NAME, open); 70 | } 71 | 72 | 73 | // ---------------------------------------- 74 | // DocImportsModel 75 | // ---------------------------------------- 76 | 77 | class DocImportsModel : public QSqlTableModel 78 | { 79 | Q_OBJECT 80 | 81 | public: 82 | DocImportsModel(QObject *parent = nullptr, RecordType type = RecordType::Unknown) 83 | : QSqlTableModel(parent, getConnection()) 84 | { 85 | setEditStrategy(QSqlTableModel::OnManualSubmit); 86 | //qDebug() << "Opened DB" << database().connectionName() << database().databaseName(); 87 | if (type != RecordType::Unknown) 88 | setRecordType(type); 89 | } 90 | 91 | RecordType recordType() const { return m_recordType; } 92 | 93 | QDateTime lastDataUpdate(RecordType type, QString *fromUrl = nullptr) 94 | { 95 | QDateTime lu; 96 | if (type == RecordType::Unknown) 97 | return lu; 98 | 99 | const QString table(QMetaEnum::fromType().valueToKey(type)); 100 | QSqlQuery qry("SELECT LastUpdate, FromURL FROM ImportMeta WHERE TableName = ? ", database()); 101 | qry.addBindValue(table); 102 | qry.exec(); 103 | if (qry.next()) { 104 | lu = qry.value(0).toDateTime(); 105 | lu.setTimeZone(QTimeZone::utc()); 106 | lu = lu.toLocalTime(); 107 | if (fromUrl) 108 | *fromUrl = qry.value(1).toString(); 109 | } 110 | else if (qry.lastError().isValid()) { 111 | qDebug() << "ImportMeta query for table" << table << "failed with:" << qry.lastError(); 112 | } 113 | else { 114 | qDebug() << "ImportMeta query for table" << table << "returned no results."; 115 | } 116 | qry.finish(); 117 | return lu; 118 | } 119 | 120 | void setRecordType(RecordType type) 121 | { 122 | m_recordType = type; 123 | QString table; 124 | switch (type) { 125 | case RecordType::SimVars: 126 | case RecordType::KeyEvents: 127 | case RecordType::SimVarUnits: 128 | table = QString(QMetaEnum::fromType().valueToKey(type)); 129 | break; 130 | 131 | default: 132 | return; 133 | } 134 | 135 | setTable(table); 136 | select(); 137 | 138 | //setQuery("SELECT * FROM " + table, m_db); 139 | if (lastError().isValid()) { 140 | qDebug() << "Query for table" << table << "failed with: " << lastError(); 141 | return; 142 | } 143 | 144 | removeColumnName("Multiplayer"); 145 | removeColumnName("Deprecated"); 146 | } 147 | 148 | void removeColumnName(const QString &name) { 149 | const int col = fieldIndex(name); 150 | if (col > -1) 151 | removeColumn(col); 152 | } 153 | 154 | Qt::ItemFlags flags(const QModelIndex &idx) const override { 155 | if (idx.isValid()) 156 | return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren; 157 | return Qt::NoItemFlags; 158 | } 159 | 160 | QVariant data(const QModelIndex &idx, int role) const override { 161 | if (role == Qt::ToolTipRole) 162 | role = Qt::DisplayRole; 163 | return QSqlTableModel::data(idx, role); 164 | } 165 | 166 | QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override { 167 | if (role == Qt::EditRole || role == Qt::ToolTipRole) 168 | return QSqlTableModel::headerData(section, orientation, Qt::DisplayRole); 169 | return QSqlTableModel::headerData(section, orientation, role); 170 | } 171 | 172 | private: 173 | RecordType m_recordType = RecordType::Unknown; 174 | 175 | }; 176 | 177 | 178 | // ---------------------------------------- 179 | // NameCompleter 180 | // ---------------------------------------- 181 | 182 | class NameCompleter : public QCompleter 183 | { 184 | Q_OBJECT 185 | 186 | public: 187 | NameCompleter(RecordType recordType, QObject *parent = nullptr) : 188 | QCompleter(parent) 189 | { 190 | DocImportsModel *m = new DocImportsModel(this, recordType); 191 | const int modelColumn = m->fieldIndex("Name"); 192 | if (recordType != RecordType::SimVarUnits) 193 | m->setFilter(QStringLiteral("Deprecated = 0")); 194 | m->setSort(modelColumn, Qt::AscendingOrder); 195 | 196 | setModel(m); 197 | setCompletionColumn(modelColumn); 198 | setModelSorting(QCompleter::CaseSensitivelySortedModel); 199 | setCompletionMode(QCompleter::PopupCompletion); 200 | setCaseSensitivity(Qt::CaseInsensitive); 201 | setFilterMode(Qt::MatchContains); 202 | setMaxVisibleItems(12); 203 | } 204 | 205 | DocImportsModel *model() const { return (DocImportsModel *)QCompleter::model(); } 206 | 207 | }; 208 | 209 | 210 | // ---------------------------------------- 211 | // RecordTypeComboBox 212 | // ---------------------------------------- 213 | 214 | class RecordTypeComboBox : public EnumsComboBox 215 | { 216 | public: 217 | RecordTypeComboBox(QWidget *p = nullptr) : 218 | EnumsComboBox(DocImports::RecordTypeNames, DocImports::RecordType::SimVars, p) { 219 | setToolTip(tr("Select a documentation record type to browse.")); 220 | } 221 | }; 222 | 223 | } // DocImports 224 | } // WASimUiNS 225 | -------------------------------------------------------------------------------- /src/WASimUI/DocImportsBrowser.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | DocImportsBrowserClass 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1170 10 | 660 11 | 12 | 13 | 14 | DocImportsBrowser 15 | 16 | 17 | 18 | 19 | 20 | 21 | 0 22 | 23 | 24 | 0 25 | 26 | 27 | 28 | 29 | Select Record Type: 30 | 31 | 32 | cbRecordType 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 0 44 | 0 45 | 46 | 47 | 48 | 49 | 8 50 | 51 | 52 | 53 | Data is imported from SimConnect SDK web page documentation. Use the filters in each column to search (hover or r-click on them for details). 54 | 55 | 56 | Qt::AlignCenter 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 0 75 | 0 76 | 77 | 78 | 79 | Qt::Horizontal 80 | 81 | 82 | 6 83 | 84 | 85 | 86 | 87 | QAbstractScrollArea::AdjustToContents 88 | 89 | 90 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 91 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> 92 | p, li { white-space: pre-wrap; } 93 | </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> 94 | <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Select a record from the table to view details here.</span></p></body></html> 95 | 96 | 97 | Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse 98 | 99 | 100 | true 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | BuddyLabel 111 | QLabel 112 |
BuddyLabel.h
113 |
114 | 115 | WASimUiNS::CustomTableView 116 | QTableView 117 |
CustomTableView.h
118 |
119 | 120 | WASimUiNS::DocImports::RecordTypeComboBox 121 | QComboBox 122 |
DocImports.h
123 |
124 |
125 | 126 | cbRecordType 127 | tableView 128 | textBrowser 129 | 130 | 131 | 132 |
133 | -------------------------------------------------------------------------------- /src/WASimUI/EventsModel.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of the GNU General Public License (GPL) 8 | as published by the Free Software Foundation, either version 3 of the Licenses, 9 | or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | A copy of the GNU GPL is included with this project 17 | and is also available at . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "client/WASimClient.h" 30 | #include "Utils.h" 31 | 32 | namespace WASimUiNS 33 | { 34 | 35 | // ------------------------------------------------------------- 36 | // EventRecord 37 | // ------------------------------------------------------------- 38 | 39 | /// Registered Calculator Event 40 | struct EventRecord : public WASimCommander::Client::RegisteredEvent 41 | { 42 | using WASimCommander::Client::RegisteredEvent::RegisteredEvent; 43 | 44 | /// QDataStream operator for serializing to a QVariant (eg. for QSettings storage). 45 | friend QDataStream& operator<<(QDataStream& out, const EventRecord &r) 46 | { 47 | return out << r.eventId << QString::fromStdString(r.code) << QString::fromStdString(r.name); 48 | } 49 | 50 | /// QDataStream operator for deserializing from a QVariant (eg. for QSettings storage). 51 | friend QDataStream& operator>>(QDataStream& in, EventRecord &r) 52 | { 53 | QString c, n; 54 | in >> r.eventId; 55 | in >> c; 56 | in >> n; 57 | r.code = c.toStdString(); 58 | r.name = n.toStdString(); 59 | return in; 60 | } 61 | 62 | }; 63 | Q_DECLARE_METATYPE(EventRecord) 64 | 65 | 66 | // ------------------------------------------------------------- 67 | // EventsModel 68 | // ------------------------------------------------------------- 69 | 70 | /// The EventsModel handles storage and retrieval of EventRecord types. 71 | class EventsModel : public QStandardItemModel 72 | { 73 | private: 74 | Q_OBJECT 75 | enum Roles { DataRole = Qt::UserRole + 1, StatusRole }; 76 | 77 | public: 78 | enum Columns { 79 | COL_ID, COL_CODE, COL_NAME, COL_ENUM_END 80 | }; 81 | const QStringList columnNames = { 82 | tr("ID"), tr("Code"), tr("Name"), 83 | }; 84 | 85 | EventsModel(QObject *parent = nullptr) : 86 | QStandardItemModel(0, COL_ENUM_END, parent) 87 | { 88 | setHorizontalHeaderLabels(columnNames); 89 | connect(this, &QAbstractItemModel::rowsInserted, this, [=](const QModelIndex &, int, int) { emit rowCountChanged(rowCount()); }); 90 | connect(this, &QAbstractItemModel::rowsRemoved, this, [=](const QModelIndex &, int, int) { emit rowCountChanged(rowCount()); }); 91 | } 92 | 93 | uint32_t nextEventId() { return m_nextEventId++; } 94 | 95 | uint32_t eventId(int row) const { 96 | if (row >= rowCount()) 97 | return uint32_t(-1); 98 | return item(row, COL_ID)->data(DataRole).toUInt(); 99 | } 100 | 101 | EventRecord getEvent(int row) const 102 | { 103 | EventRecord req(-1); 104 | if (row >= rowCount()) 105 | return req; 106 | req.eventId = item(row, COL_ID)->data(DataRole).toUInt(); 107 | req.code = item(row, COL_CODE)->text().toStdString(); 108 | req.name = item(row, COL_NAME)->text().toStdString(); 109 | return req; 110 | } 111 | 112 | QModelIndex addEvent(const EventRecord &req) 113 | { 114 | int row = findRow(req.eventId); 115 | if (row < 0) 116 | row = rowCount(); 117 | 118 | setOrCreateItem(row, COL_ID, QString::number(req.eventId), req.eventId); 119 | setOrCreateItem(row, COL_CODE, QString::fromStdString(req.code)); 120 | setOrCreateItem(row, COL_NAME, QString::fromStdString(req.name)); 121 | return index(row, 0); 122 | } 123 | 124 | void removeEvent(const uint32_t eventId) 125 | { 126 | const int row = findRow(eventId); 127 | if (row > -1) 128 | removeRow(row); 129 | } 130 | 131 | void removeEvents(const QList eventIds) 132 | { 133 | for (const uint32_t id : eventIds) 134 | removeEvent(id); 135 | } 136 | 137 | void removeEvents(const QModelIndexList &indexes) 138 | { 139 | QList rows; 140 | rows.reserve(indexes.count()); 141 | for (const QModelIndex &idx : indexes) 142 | rows.append(idx.row()); 143 | std::sort(rows.begin(), rows.end(), std::greater()); 144 | for (const int row : rows) 145 | removeRow(row); 146 | } 147 | 148 | int saveToFile(const QString &filepath) 149 | { 150 | const int rows = rowCount(); 151 | if (!rows) 152 | return rows; 153 | QSettings s(filepath, QSettings::IniFormat); 154 | s.setAtomicSyncRequired(false); 155 | s.beginGroup(QStringLiteral("Events")); 156 | s.remove(""); 157 | for (int i = 0; i < rows; ++i) 158 | s.setValue(QStringLiteral("%1").arg(i), QVariant::fromValue(getEvent(i))); 159 | s.endGroup(); 160 | s.sync(); 161 | return rows; 162 | } 163 | 164 | QList loadFromFile(const QString &filepath) 165 | { 166 | QList ret; 167 | QSettings s(filepath, QSettings::IniFormat); 168 | s.setAtomicSyncRequired(false); 169 | s.beginGroup(QStringLiteral("Events")); 170 | const QStringList list = s.childKeys(); 171 | for (const QString &key : list) { 172 | EventRecord req = s.value(key).value(); 173 | req.eventId = nextEventId(); 174 | addEvent(req); 175 | ret << req; 176 | } 177 | s.endGroup(); 178 | return ret; 179 | } 180 | 181 | signals: 182 | void rowCountChanged(int rows); 183 | 184 | protected: 185 | QStandardItem *setOrCreateItem(int row, int col, const QString &text, const QVariant &data = QVariant()) 186 | { 187 | QStandardItem *itm = item(row, col); 188 | if (!itm){ 189 | setItem(row, col, new QStandardItem()); 190 | itm = item(row, col); 191 | } 192 | itm->setText(text); 193 | itm->setToolTip(text); 194 | if (data.isValid()) 195 | itm->setData(data, DataRole); 196 | return itm; 197 | } 198 | 199 | private: 200 | uint32_t m_nextEventId = 0; 201 | 202 | int findRow(uint32_t eventId) const 203 | { 204 | if (rowCount()) { 205 | const QModelIndexList src = match(index(0, COL_ID), DataRole, eventId, 1, Qt::MatchExactly); 206 | //qDebug() << eventId << src << (!src.isEmpty() ? src.first() : QModelIndex()); 207 | if (!src.isEmpty()) 208 | return src.first().row(); 209 | } 210 | return -1; 211 | } 212 | 213 | }; 214 | 215 | } 216 | -------------------------------------------------------------------------------- /src/WASimUI/LogConsole.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of the GNU General Public License (GPL) 8 | as published by the Free Software Foundation, either version 3 of the Licenses, 9 | or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | A copy of the GNU GPL is included with this project 17 | and is also available at . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include "ui_LogConsole.h" 25 | #include "LogRecordsModel.h" 26 | #include "WASimCommander.h" 27 | 28 | class WASimCommander::Client::WASimClient; 29 | 30 | namespace WASimUiNS { 31 | 32 | class LogConsole : public QWidget 33 | { 34 | Q_OBJECT 35 | 36 | public: 37 | LogConsole(QWidget *parent = nullptr); 38 | ~LogConsole(); 39 | 40 | void setClient(WASimCommander::Client::WASimClient *c); 41 | WASimUiNS::LogRecordsModel *getModel() const; 42 | 43 | public Q_SLOTS: 44 | void saveSettings() const; 45 | void loadSettings(); 46 | void logMessage(int level, const QString &msg) const; 47 | 48 | signals: 49 | void logMessageReady(const WASimCommander::LogRecord &r, quint8 src) const; 50 | 51 | private: 52 | Ui::LogConsole ui; 53 | WASimUiNS::LogRecordsModel *logModel = nullptr; 54 | WASimCommander::Client::WASimClient *wsClient = nullptr; 55 | }; 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/WASimUI/LogRecordsModel.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of the GNU General Public License (GPL) 8 | as published by the Free Software Foundation, either version 3 of the Licenses, 9 | or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | A copy of the GNU GPL is included with this project 17 | and is also available at . 18 | */ 19 | 20 | #pragma once 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "client/WASimClient.h" 27 | #include "Utils.h" 28 | 29 | namespace WASimUiNS 30 | { 31 | 32 | /// The LogRecordsModel handles storage, sorting, and filtering of `LogRecord` types. 33 | class LogRecordsModel : public QSortFilterProxyModel 34 | { 35 | private: 36 | Q_OBJECT 37 | enum Roles { DataRole = Qt::UserRole + 1, LevelRole, SourceRole }; 38 | 39 | public: 40 | enum class LogSource : uint8_t { 41 | Client = +WASimCommander::Client::LogSource::Client, Server = +WASimCommander::Client::LogSource::Server, UI 42 | }; 43 | const QStringList LogSourceEnumNames = { "Client", "Server", "UI" }; 44 | 45 | enum Columns { 46 | COL_LEVEL, COL_TS, COL_SOURCE, COL_MESSAGE, COL_ENUM_END 47 | }; 48 | const QStringList columnNames = { 49 | tr("Level"), tr("Time"), tr("Src"), tr("Message") 50 | }; 51 | 52 | const QStringList levelNames = { "NON", "CRT", "ERR", "WRN", "INF", "DBG", "TRC" }; 53 | const QStringList levelBgColors = { "black", "#3fea00ff", "#3bff0000", "#4da08300", "#21006eff", "#3ba4b1b3", "transparent" }; 54 | 55 | LogRecordsModel(QObject *parent = nullptr) : 56 | QSortFilterProxyModel(parent), 57 | m_model(new QStandardItemModel(0, COL_ENUM_END, this)) 58 | { 59 | m_model->setHorizontalHeaderLabels(columnNames); 60 | setSourceModel(m_model); 61 | 62 | setSortRole(DataRole); 63 | sort(COL_TS, Qt::AscendingOrder); 64 | 65 | connect(this, &QAbstractItemModel::rowsInserted, this, [=](const QModelIndex &, int, int) { emit rowCountChanged(rowCount()); }); 66 | connect(this, &QAbstractItemModel::rowsRemoved, this, [=](const QModelIndex &, int, int) { emit rowCountChanged(rowCount()); }); 67 | } 68 | 69 | void addRecord(const WASimCommander::LogRecord &log, quint8 src) 70 | { 71 | const int row = m_model->rowCount(); 72 | 73 | m_model->setItem(row, COL_LEVEL, new QStandardItem(QIcon(Utils::iconNameForLogLevel(log.level)), Utils::getEnumName(log.level, levelNames))); 74 | m_model->item(row, COL_LEVEL)->setToolTip(Utils::getEnumName(log.level, WSEnums::LogLevelNames)); 75 | m_model->item(row, COL_LEVEL)->setTextAlignment(Qt::AlignCenter); 76 | m_model->item(row, COL_LEVEL)->setData(+log.level, LevelRole); 77 | m_model->item(row, COL_LEVEL)->setData(src, SourceRole); 78 | 79 | const QDateTime dt = QDateTime::fromMSecsSinceEpoch(log.timestamp); 80 | m_model->setItem(row, COL_TS, new QStandardItem(dt.toString("hh:mm:ss.zzz"))); 81 | m_model->item(row, COL_TS)->setToolTip(dt.toString("ddd MMMM d")); 82 | m_model->item(row, COL_TS)->setData(dt, DataRole); 83 | 84 | m_model->setItem(row, COL_SOURCE, new QStandardItem(QIcon(Utils::iconNameForLogSource(src)), "")); 85 | m_model->item(row, COL_SOURCE)->setToolTip(tr("Log Source: %1").arg(Utils::getEnumName(src, LogSourceEnumNames))); 86 | //m_model->item(row, COL_SOURCE)->setTextAlignment(Qt::AlignCenter); 87 | 88 | const QString msg(log.message); 89 | m_model->setItem(row, COL_MESSAGE, new QStandardItem(msg)); 90 | m_model->item(row, COL_MESSAGE)->setToolTip(msg); 91 | 92 | decorateStatus(row, log.level, (LogSource)src); 93 | 94 | emit recordAdded(mapFromSource(m_model->index(row, 0))); 95 | } 96 | 97 | void clear() { 98 | m_model->removeRows(0, rowCount()); 99 | } 100 | 101 | void addLevelFilter(WSEnums::LogLevel l) 102 | { 103 | if (!m_exludeLevels.contains(+l)) { 104 | m_exludeLevels.append(+l); 105 | invalidateFilter(); 106 | } 107 | } 108 | 109 | void removeLevelFilter(WSEnums::LogLevel l) 110 | { 111 | const int idx = m_exludeLevels.indexOf(+l); 112 | if (idx > -1) { 113 | m_exludeLevels.remove(idx); 114 | invalidateFilter(); 115 | } 116 | } 117 | 118 | void setLevelFilter(WSEnums::LogLevel l, bool enable) 119 | { 120 | if (enable) 121 | addLevelFilter(l); 122 | else 123 | removeLevelFilter(l); 124 | } 125 | 126 | void addSourceFilter(uint8_t s) 127 | { 128 | if (!m_exludeSources.contains(s)) { 129 | m_exludeSources.append(s); 130 | invalidateFilter(); 131 | } 132 | } 133 | 134 | void removeSourceFilter(uint8_t s) 135 | { 136 | const int idx = m_exludeSources.indexOf(s); 137 | if (idx > -1) { 138 | m_exludeSources.remove(idx); 139 | invalidateFilter(); 140 | } 141 | } 142 | 143 | void setSourceFilter(uint8_t s, bool enable) 144 | { 145 | if (enable) 146 | addSourceFilter(s); 147 | else 148 | removeSourceFilter(s); 149 | } 150 | 151 | signals: 152 | void rowCountChanged(int rows); 153 | void recordAdded(const QModelIndex &index); 154 | 155 | protected: 156 | bool filterAcceptsRow(int row, const QModelIndex &) const override 157 | { 158 | QStandardItem *item = m_model->item(row, COL_LEVEL); 159 | if (!item) 160 | return false; 161 | return !m_exludeLevels.contains(item->data(LevelRole).toUInt()) && !m_exludeSources.contains(item->data(SourceRole).toUInt()); 162 | } 163 | 164 | private: 165 | void decorateStatus(const int row, WSEnums::LogLevel l, LogSource s) 166 | { 167 | if (QStandardItem *item = m_model->item(row, COL_LEVEL)) 168 | item->setBackground(QColor(Utils::getEnumName(l, levelBgColors))); 169 | } 170 | 171 | QStandardItemModel *m_model; 172 | QVector m_exludeLevels {}; 173 | QVector m_exludeSources {}; 174 | 175 | }; 176 | 177 | } 178 | -------------------------------------------------------------------------------- /src/WASimUI/README.md: -------------------------------------------------------------------------------- 1 | 2 | # WASimCommander 3 | ## WASimUI - Desktop Application Companion for Testing and Exploring WASimCommander Features 4 | 5 | This directory contains a full-featured GUI application which makes use of all available features of the WASimCommander Client API. 6 | Primarily designed for testing the WASimCommander system, it also includes many usability features designed for "real world" use to 7 | examine running Simulator state. 8 | 9 | The GUI uses portions of the [_Qt Library_](http://qt.io) under the terms of the GPL v3 license. 10 | 11 | Building requires MSVS (2019 or 2022) with Qt VSTools extention and a recent Qt v5 installation (tested with `5.12.12`, `5.14.2`). Qt v6 is _not_ supported. 12 | -------------------------------------------------------------------------------- /src/WASimUI/RequestsExport.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of the GNU General Public License (GPL) 8 | as published by the Free Software Foundation, either version 3 of the Licenses, 9 | or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | A copy of the GNU GPL is included with this project 17 | and is also available at . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include "ui_RequestsExport.h" 24 | #include "DataComboBox.h" 25 | 26 | namespace WASimUiNS { 27 | 28 | class RequestsModel; 29 | 30 | class RequestsExportWidget : public QWidget 31 | { 32 | Q_OBJECT 33 | 34 | public: 35 | explicit RequestsExportWidget(RequestsModel *model, QWidget *parent = nullptr); 36 | RequestsModel *model() const; 37 | 38 | public Q_SLOTS: 39 | void setLastUsedFile(const QString &fn) { m_lastFile = fn; }; 40 | void exportAll(); 41 | void exportSelected(); 42 | 43 | Q_SIGNALS: 44 | void lastUsedFileChanged(const QString &fn); 45 | 46 | protected: 47 | void closeEvent(QCloseEvent *) override; 48 | 49 | private: 50 | void setModel(RequestsModel *model); 51 | void exportRecords(bool all = true); 52 | void ensureDefaultValues(); 53 | void updateBulk(); 54 | void regenIds(); 55 | void regenNames(); 56 | void clearForm(); 57 | void saveSettings() const; 58 | void loadSettings(); 59 | 60 | QString m_lastFile; 61 | RequestsModel *m_model = nullptr; 62 | Ui::RequestsExport ui; 63 | }; 64 | 65 | } // WASimUiNS 66 | -------------------------------------------------------------------------------- /src/WASimUI/RequestsTableView.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of the GNU General Public License (GPL) 8 | as published by the Free Software Foundation, either version 3 of the Licenses, 9 | or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | A copy of the GNU GPL is included with this project 17 | and is also available at . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "CustomTableView.h" 29 | 30 | #include "RequestsModel.h" 31 | #include "Widgets.h" 32 | 33 | namespace WASimUiNS 34 | { 35 | 36 | class CategoryDelegate : public QStyledItemDelegate 37 | { 38 | Q_OBJECT 39 | public: 40 | QMap textDataMap {}; 41 | 42 | using QStyledItemDelegate::QStyledItemDelegate; 43 | 44 | QWidget *createEditor(QWidget *p, const QStyleOptionViewItem &opt, const QModelIndex &index) const override 45 | { 46 | DataComboBox *cb = new DataComboBox(p); 47 | cb->addItems(textDataMap); 48 | connect(cb, &DataComboBox::currentTextChanged, this, &CategoryDelegate::commit); 49 | return cb; 50 | } 51 | 52 | void setEditorData(QWidget *editor, const QModelIndex &index) const override { 53 | editor->setProperty("currentText", index.data(Qt::EditRole)); 54 | } 55 | void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override { 56 | model->setData(index, editor->property("currentText"), Qt::EditRole); 57 | model->setData(index, editor->property("currentData"), Qt::ToolTipRole); 58 | } 59 | 60 | void commit() { 61 | if (DataComboBox *cb = qobject_cast(sender())) 62 | emit commitData(cb); 63 | } 64 | }; 65 | 66 | class RequestsTableView : public CustomTableView 67 | { 68 | Q_OBJECT 69 | 70 | public: 71 | RequestsTableView(QWidget *parent) 72 | : CustomTableView(parent), 73 | m_cbCategoryDelegate{new CategoryDelegate(this)} 74 | { 75 | setObjectName(QStringLiteral("RequestsTableView")); 76 | 77 | } 78 | 79 | public Q_SLOTS: 80 | void setExportCategories(const QMap &map) { m_cbCategoryDelegate->textDataMap = map; } 81 | 82 | void setModel(RequestsModel *model) 83 | { 84 | CustomTableView::setModel(model); 85 | 86 | QHeaderView *hdr = horizontalHeader(); 87 | hdr->resizeSection(RequestsModel::COL_ID, 40); 88 | hdr->resizeSection(RequestsModel::COL_TYPE, 65); 89 | hdr->resizeSection(RequestsModel::COL_RES_TYPE, 55); 90 | hdr->resizeSection(RequestsModel::COL_NAME, 265); 91 | hdr->resizeSection(RequestsModel::COL_IDX, 30); 92 | hdr->resizeSection(RequestsModel::COL_UNIT, 55); 93 | hdr->resizeSection(RequestsModel::COL_SIZE, 85); 94 | hdr->resizeSection(RequestsModel::COL_PERIOD, 60); 95 | hdr->resizeSection(RequestsModel::COL_INTERVAL, 40); 96 | hdr->resizeSection(RequestsModel::COL_EPSILON, 60); 97 | hdr->resizeSection(RequestsModel::COL_VALUE, 70); 98 | hdr->resizeSection(RequestsModel::COL_TIMESATMP, 70); 99 | 100 | hdr->resizeSection(RequestsModel::COL_META_ID, 130); 101 | hdr->resizeSection(RequestsModel::COL_META_NAME, 175); 102 | hdr->resizeSection(RequestsModel::COL_META_CAT, 110); 103 | hdr->resizeSection(RequestsModel::COL_META_DEF, 70); 104 | hdr->resizeSection(RequestsModel::COL_META_FMT, 50); 105 | 106 | setItemDelegateForColumn(RequestsModel::COL_META_CAT, m_cbCategoryDelegate); 107 | } 108 | 109 | private: 110 | CategoryDelegate *m_cbCategoryDelegate; 111 | }; 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/WASimUI/SimConnect.cfg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpaperno/WASimCommander/b156aba09128b7c899e27456bfbded5c46bfcbad/src/WASimUI/SimConnect.cfg -------------------------------------------------------------------------------- /src/WASimUI/WASimUI.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpaperno/WASimCommander/b156aba09128b7c899e27456bfbded5c46bfcbad/src/WASimUI/WASimUI.aps -------------------------------------------------------------------------------- /src/WASimUI/WASimUI.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of the GNU General Public License (GPL) 8 | as published by the Free Software Foundation, either version 3 of the Licenses, 9 | or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | A copy of the GNU GPL is included with this project 17 | and is also available at . 18 | */ 19 | 20 | #pragma once 21 | #include 22 | #include "ui_WASimUI.h" 23 | #include "client/WASimClient.h" 24 | 25 | class WASimUIPrivate; 26 | 27 | class WASimUI : public QMainWindow 28 | { 29 | Q_OBJECT 30 | 31 | public: 32 | WASimUI(QWidget *parent = Q_NULLPTR); 33 | ~WASimUI(); 34 | 35 | signals: 36 | void clientEvent(const WASimCommander::Client::ClientEvent &ev); 37 | void commandResultReady(const WASimCommander::Command &c); 38 | void listResults(const WASimCommander::Client::ListResult &list); 39 | void dataResultReady(const WASimCommander::Client::DataRequestRecord &r); 40 | 41 | protected: 42 | void closeEvent(QCloseEvent *) override; 43 | void onClientEvent(const WASimCommander::Client::ClientEvent &ev); 44 | void onListResults(const WASimCommander::Client::ListResult &list); 45 | 46 | private: 47 | Ui::WASimUIClass ui; 48 | QScopedPointer d; 49 | friend class WASimUIPrivate; 50 | }; 51 | -------------------------------------------------------------------------------- /src/WASimUI/WASimUI.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | resources/MaterialIcons-Regular.ttf 4 | resources/IcoMoon-Free.ttf 5 | 6 | 7 | resources/materialicons.cmap.json 8 | resources/icomooon.cmap.json 9 | 10 | 11 | resources/WASim-Logo_96.png 12 | 13 | 14 | resources/style.css 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/WASimUI/WASimUI.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "resources/WASim.ico" 2 | -------------------------------------------------------------------------------- /src/WASimUI/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of the GNU General Public License (GPL) 8 | as published by the Free Software Foundation, either version 3 of the Licenses, 9 | or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | A copy of the GNU GPL is included with this project 17 | and is also available at . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #ifdef Q_OS_WIN 24 | #define WIN32_LEAN_AND_MEAN 25 | #include 26 | #endif 27 | 28 | #include "WASimUI.h" 29 | #include "Utils.h" 30 | 31 | #define MESSAGE_LOG_PATTERN \ 32 | "[%{time process}]" \ 33 | "[%{if-debug}--%{endif}%{if-info}++%{endif}%{if-warning}!!%{endif}%{if-critical}**%{endif}%{if-fatal}XX%{endif}] " \ 34 | "%{function}() @%{line} - %{message}" 35 | 36 | int main(int argc, char *argv[]) 37 | { 38 | #ifdef Q_OS_WIN 39 | // if started from console/CLI then reopen stdout/stderr pipes to it for logging. 40 | if (AttachConsole(ATTACH_PARENT_PROCESS)) { 41 | freopen("CONOUT$", "w", stdout); 42 | freopen("CONOUT$", "w", stderr); 43 | } 44 | #endif 45 | 46 | // configure GlyphIconEngine options 47 | qputenv("GI_LOAD_FONTS_FROM", QByteArrayLiteral(":/fonts")); 48 | qputenv("GI_LOAD_CMAPS_FROM", QByteArrayLiteral(":/cmaps")); 49 | qputenv("GI_DEFAULT_FONT", QByteArrayLiteral("Material Icons")); 50 | //qputenv("GI_DYNAMIC_POLISH", QByteArrayLiteral("0")); 51 | //qputenv("GI_NO_PAINT_CACHE", QByteArrayLiteral("0")); 52 | 53 | // all our images are scalable 54 | qputenv("QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING", QByteArrayLiteral("1")); 55 | 56 | // configure logging categories 57 | //QLoggingCategory::setFilterRules(QStringLiteral( 58 | //"glyphIcon.*.info = true\n" 59 | //"glyphIcon.*.debug = true\n" 60 | //)); 61 | // set up message logging pattern 62 | qSetMessagePattern(MESSAGE_LOG_PATTERN); 63 | 64 | QApplication::setStyle("Fusion"); // things style better with Fusion 65 | QApplication a(argc, argv); 66 | QApplication::setOrganizationName(WSMCMND_PROJECT_NAME); 67 | //QApplication::setOrganizationDomain(WSMCMND_PROJECT_URL); 68 | QApplication::setApplicationName(WSMCMND_GUI_NAME); 69 | QApplication::setApplicationDisplayName(WSMCMND_APP_NAME); 70 | QApplication::setApplicationVersion(WSMCMND_VERSION_STR); 71 | QApplication::setWindowIcon(WASimUiNS::Utils::appIcon()); 72 | #ifdef Q_OS_WIN 73 | // Qt default MS Shell Dlg font is wrong. 74 | QApplication::setFont(QFont(QStringLiteral("Segoe UI"), 9)); 75 | #endif 76 | 77 | QSettings::setDefaultFormat(QSettings::IniFormat); 78 | 79 | WASimUI w; // will show() itself 80 | 81 | a.setQuitOnLastWindowClosed(true); 82 | return a.exec(); 83 | } 84 | -------------------------------------------------------------------------------- /src/WASimUI/model/AlphanumComparer.h: -------------------------------------------------------------------------------- 1 | #ifndef ALPHANUMCOMPARER_H 2 | #define ALPHANUMCOMPARER_H 3 | 4 | /*! 5 | * \brief Natural (alpha-num) sorting 6 | * \author Litkevich Yuriy 7 | * \see http://www.forum.crossplatform.ru/index.php?showtopic=6244&st=0&p=44752&#entry44752 8 | */ 9 | 10 | 11 | #include 12 | 13 | 14 | class AlphanumComparer 15 | { 16 | public: 17 | static bool lessThan(const QString &s1, const QString &s2) 18 | { 19 | return compare( s1, s2 ) < 0 ; 20 | } 21 | 22 | private: 23 | /*! 24 | * \fn compare - compare two strings 25 | * \param l - left sring. 26 | * \param r - right string. 27 | * 28 | * \return 29 | * lr - result more than zero; 31 | * l=r - result is zero. 32 | */ 33 | static int compare(QString l, QString r) 34 | { 35 | enum Mode { STRING, NUMBER } mode = STRING; 36 | 37 | int size; 38 | if ( l.size() < r.size() ) 39 | size = l.size(); 40 | else 41 | size = r.size(); 42 | 43 | int i = 0; 44 | 45 | // runing throught both strings to position "size-1" 46 | while( i < size) { 47 | if ( mode == STRING ) { 48 | QChar lchar, rchar; 49 | bool ldigit, rdigit; 50 | while( i < size ) { 51 | lchar = l.at( i ); 52 | rchar = r.at( i ); 53 | ldigit = lchar.isDigit(); 54 | rdigit = rchar.isDigit(); 55 | // if both simbols is numbers, using numbers state 56 | if ( ldigit && rdigit ) { 57 | mode = NUMBER; 58 | break; 59 | } 60 | if ( ldigit ) return -1; 61 | if ( rdigit ) return +1; 62 | // both simbols are letters 63 | if ( lchar < rchar ) return -1; 64 | if ( lchar > rchar ) return +1; 65 | // simbols are equal 66 | i++; 67 | } 68 | } else { //mode == NUMBER 69 | unsigned long long lnum = 0, rnum = 0; 70 | int li = i, ri = i; // local indexes 71 | int ld = 0, rd = 0; // numbers 72 | 73 | // make left number 74 | while ( li < l.size() ) { 75 | ld = l.at( li ).digitValue(); 76 | if ( ld < 0 ) break; 77 | lnum = lnum*10 + ld; 78 | li++; 79 | } 80 | 81 | // make right number 82 | while( ri < r.size() ) { 83 | rd = r.at( ri ).digitValue(); 84 | if ( rd < 0 ) break; 85 | rnum = rnum*10 + rd; 86 | ri++; 87 | } 88 | 89 | long long delta = lnum - rnum; 90 | if ( delta ) return delta; 91 | 92 | // numbers are equal 93 | mode = STRING; 94 | if ( li <= ri ) 95 | i=li; 96 | else 97 | i=ri; 98 | } 99 | } 100 | // this is for situation when both strings to position "size-1" equals 101 | if ( i < r.size() ) return -1; 102 | if (i < l.size() ) return +1; 103 | 104 | // strings are full equal 105 | return 0; 106 | } 107 | }; 108 | 109 | #endif // ALPHANUMCOMPARER_H 110 | -------------------------------------------------------------------------------- /src/WASimUI/resources/IcoMoon-Free.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpaperno/WASimCommander/b156aba09128b7c899e27456bfbded5c46bfcbad/src/WASimUI/resources/IcoMoon-Free.ttf -------------------------------------------------------------------------------- /src/WASimUI/resources/MSFS_SDK_Doc_Import.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpaperno/WASimCommander/b156aba09128b7c899e27456bfbded5c46bfcbad/src/WASimUI/resources/MSFS_SDK_Doc_Import.sqlite3 -------------------------------------------------------------------------------- /src/WASimUI/resources/MaterialIcons-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpaperno/WASimCommander/b156aba09128b7c899e27456bfbded5c46bfcbad/src/WASimUI/resources/MaterialIcons-Regular.ttf -------------------------------------------------------------------------------- /src/WASimUI/resources/WASim-Logo_96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpaperno/WASimCommander/b156aba09128b7c899e27456bfbded5c46bfcbad/src/WASimUI/resources/WASim-Logo_96.png -------------------------------------------------------------------------------- /src/WASimUI/resources/WASim.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpaperno/WASimCommander/b156aba09128b7c899e27456bfbded5c46bfcbad/src/WASimUI/resources/WASim.ico -------------------------------------------------------------------------------- /src/WASimUI/resources/style.css: -------------------------------------------------------------------------------- 1 | QDockWidget { 2 | border: 1px solid palette(mid); 3 | titlebar-close-icon: url(close.glyph); 4 | titlebar-normal-icon: url(open_in_new.glyph); 5 | } 6 | 7 | QDockWidget::title{ 8 | padding:4px; 9 | border:1px solid palette(mid); 10 | border-bottom:0; 11 | } 12 | 13 | QDockWidget::close-button, 14 | QDockWidget::float-button{ 15 | subcontrol-position:top right; 16 | subcontrol-origin:margin; 17 | position:absolute; 18 | top:3px; 19 | right:5px; 20 | width:20px; 21 | height:20px; 22 | } 23 | QDockWidget::float-button{ 24 | right:25px; 25 | } 26 | 27 | QGroupBox { 28 | border: 0 solid palette(mid); 29 | border-top-width: 1px; 30 | border-radius: 0; 31 | margin: 0; 32 | margin-top: .6em; 33 | padding: 12px 0 0; 34 | font-weight: bold; 35 | } 36 | QGroupBox::title { 37 | font-weight: bold; 38 | padding: 0 10px 0 0; 39 | subcontrol-origin: border; 40 | subcontrol-position: top left; 41 | top: -.6em; 42 | } 43 | 44 | QTableView { 45 | gridline-color: palette(mid); 46 | } 47 | 48 | QFrame[frameShape="4"], /* QFrame::HLine == 0x0004 */ 49 | QFrame[frameShape="5"] /* QFrame::VLine == 0x0005 */ 50 | { 51 | color: palette(mid); 52 | qproperty-frameShadow: Plain; 53 | } 54 | -------------------------------------------------------------------------------- /src/WASimUI/widgets/ActionPushButton.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ActionPushButton 3 | https://github.com/mpaperno/maxLibQt 4 | 5 | COPYRIGHT: (c)2019 Maxim Paperno; All Right Reserved. 6 | Contact: http://www.WorldDesign.com/contact 7 | 8 | LICENSE: 9 | 10 | Commercial License Usage 11 | Licensees holding valid commercial licenses may use this file in 12 | accordance with the terms contained in a written agreement between 13 | you and the copyright holder. 14 | 15 | GNU General Public License Usage 16 | Alternatively, this file may be used under the terms of the GNU 17 | General Public License as published by the Free Software Foundation, 18 | either version 3 of the License, or (at your option) any later version. 19 | 20 | This program is distributed in the hope that it will be useful, 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | GNU General Public License for more details. 24 | 25 | A copy of the GNU General Public License is available at . 26 | */ 27 | 28 | #include "ActionPushButton.h" 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | ActionPushButton::ActionPushButton(QAction *defaultAction, QWidget *parent) : 39 | QPushButton(parent) 40 | { 41 | setDefaultAction(defaultAction); 42 | } 43 | 44 | bool ActionPushButton::event(QEvent *e) 45 | { 46 | switch (e->type()) { 47 | case QEvent::ActionAdded: 48 | if (QActionEvent *ae = static_cast(e)) 49 | connect(ae->action(), &QAction::triggered, this, &ActionPushButton::onActionTriggered); 50 | break; 51 | 52 | case QEvent::ActionRemoved: 53 | if (QActionEvent *ae = static_cast(e)) { 54 | ae->action()->disconnect(this); 55 | if (ae->action() == m_defaultAction) 56 | setDefaultAction(nullptr); 57 | } 58 | break; 59 | 60 | case QEvent::ActionChanged: 61 | if (QActionEvent *ae = static_cast(e)) 62 | if (ae->action() == m_defaultAction) 63 | updateFromAction(m_defaultAction); 64 | break; 65 | 66 | default: 67 | break; 68 | } 69 | return QPushButton::event(e); 70 | } 71 | 72 | void ActionPushButton::paintEvent(QPaintEvent *e) 73 | { 74 | QStylePainter p(this); 75 | QStyleOptionButton option; 76 | initStyleOption(&option); 77 | if (!menu() && m_menuFromAction) 78 | option.features |= QStyleOptionButton::HasMenu; 79 | p.drawControl(QStyle::CE_PushButton, option); 80 | } 81 | 82 | void ActionPushButton::nextCheckState() 83 | { 84 | if (!m_defaultAction && isCheckable()) 85 | setChecked(!isChecked()); 86 | } 87 | 88 | void ActionPushButton::updateFromAction(QAction *action) 89 | { 90 | if (!action) 91 | return; 92 | QString buttonText = action->iconText(); 93 | // If iconText() is generated from text(), we need to remove any '&'s so they don't turn into shortcuts 94 | if (buttonText == action->text()) 95 | buttonText.replace(QLatin1String("&"), QLatin1String("")); 96 | setText(buttonText); 97 | setIcon(action->icon()); 98 | setToolTip(action->toolTip()); 99 | setStatusTip(action->statusTip()); 100 | setWhatsThis(action->whatsThis()); 101 | setCheckable(action->isCheckable()); 102 | setChecked(action->isChecked()); 103 | setEnabled(action->isEnabled()); 104 | setVisible(action->isVisible()); 105 | setAutoRepeat(action->autoRepeat()); 106 | if (!testAttribute(Qt::WA_SetFont)) { 107 | setFont(action->font()); 108 | setAttribute(Qt::WA_SetFont, false); 109 | } 110 | if (action->menu() && (!menu() || m_menuFromAction)) { 111 | m_menuFromAction = true; 112 | connect(action->menu()->menuAction(), &QAction::triggered, this, [=]() { 113 | if (m_defaultAction && m_defaultAction->menu()) 114 | m_defaultAction->menu()->popup(mapToGlobal(QPoint(0, height()))); 115 | }); 116 | } 117 | } 118 | 119 | void ActionPushButton::setDefaultAction(QAction *action) 120 | { 121 | if (m_defaultAction == action) 122 | return; 123 | 124 | bool hadDefault = !!m_defaultAction; 125 | if (!!m_defaultAction) { 126 | disconnect(this, &QPushButton::clicked, this, &ActionPushButton::onClicked); 127 | if (m_menuFromAction && m_defaultAction->menu()) 128 | disconnect(m_defaultAction->menu()->menuAction(), 0, this, 0); 129 | } 130 | m_menuFromAction = false; 131 | 132 | m_defaultAction = action; 133 | if (!action) 134 | return; 135 | 136 | if (!actions().contains(action)) 137 | addAction(action); 138 | updateFromAction(action); 139 | 140 | connect(this, &QPushButton::clicked, this, &ActionPushButton::onClicked); 141 | } 142 | 143 | void ActionPushButton::onClicked(bool checked) 144 | { 145 | if (!m_defaultAction) 146 | return; 147 | if (isCheckable()) 148 | m_defaultAction->setChecked(checked); 149 | else 150 | m_defaultAction->trigger(); 151 | } 152 | 153 | void ActionPushButton::onActionTriggered() 154 | { 155 | if (QAction *act = qobject_cast(sender())) 156 | emit triggered(act); 157 | } 158 | -------------------------------------------------------------------------------- /src/WASimUI/widgets/ActionPushButton.h: -------------------------------------------------------------------------------- 1 | /* 2 | ActionPushButton 3 | https://github.com/mpaperno/maxLibQt 4 | 5 | COPYRIGHT: (c)2019 Maxim Paperno; All Right Reserved. 6 | Contact: http://www.WorldDesign.com/contact 7 | 8 | LICENSE: 9 | 10 | Commercial License Usage 11 | Licensees holding valid commercial licenses may use this file in 12 | accordance with the terms contained in a written agreement between 13 | you and the copyright holder. 14 | 15 | GNU General Public License Usage 16 | Alternatively, this file may be used under the terms of the GNU 17 | General Public License as published by the Free Software Foundation, 18 | either version 3 of the License, or (at your option) any later version. 19 | 20 | This program is distributed in the hope that it will be useful, 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | GNU General Public License for more details. 24 | 25 | A copy of the GNU General Public License is available at . 26 | */ 27 | 28 | #ifndef ACTIONPUSHBUTTON_H 29 | #define ACTIONPUSHBUTTON_H 30 | 31 | #include 32 | 33 | class QAction; 34 | class QEvent; 35 | class QPaintEvent; 36 | 37 | /*! 38 | \brief The ActionPushButton class is a \c QPushButton which takes a default \c QAction, just like a \c QToolButton can. 39 | Like \c QToolButton, it will inherit all properties from the default \c QAction, such as text, icon, checkable status & state, 40 | tool tip, and so on. The default action can be set with \c setDefaultAction() and retrieved with \c defaultAction(). 41 | The default action can also be set using the dedicated \ref ActionPushButton(QAction *, QWidget *) constructor. 42 | 43 | It also adds a \c triggered(QAction *) signal for all \c QActions added to the button (not just the default one). 44 | */ 45 | class ActionPushButton : public QPushButton 46 | { 47 | Q_OBJECT 48 | //! Current default action, if any. Value is `nullptr` if no default action has been set. 49 | Q_PROPERTY(QAction *defaultAction READ defaultAction WRITE setDefaultAction) 50 | 51 | public: 52 | //! Inherits base class constructors. 53 | using QPushButton::QPushButton; 54 | //! Construct using \a defaultAction as the default action. 55 | explicit ActionPushButton(QAction *defaultAction, QWidget *parent = nullptr); 56 | 57 | //! Current default action, if any. Returns `nullptr` if no default action has been set. 58 | inline QAction *defaultAction() const { return m_defaultAction; } 59 | 60 | public slots: 61 | //! Sets the default action to \a action. The action is added to the widget if it hasn't been already. 62 | //! To clear the default action, pass a `nullptr` as the \a action. Clearing the default action in this way 63 | //! does *not* remove it from this widget itself. Use \c QWidget::removeAction() for that instead, which will 64 | //! also clear the default action on this button (if the action being removed is the current default, of course). 65 | void setDefaultAction(QAction *action); 66 | 67 | signals: 68 | //! Signal emitted whenever any \c QAction added to this button (with \c QWidget::addAction() or \c setDefaultAction()) is triggered. 69 | void triggered(QAction *); 70 | 71 | protected: 72 | bool event(QEvent *e) override; 73 | void paintEvent(QPaintEvent *e) override; 74 | void nextCheckState() override; 75 | 76 | private slots: 77 | void updateFromAction(QAction *action); 78 | void onClicked(bool checked = false); 79 | void onActionTriggered(); 80 | 81 | private: 82 | QAction *m_defaultAction = nullptr; 83 | bool m_menuFromAction = false; 84 | 85 | Q_DISABLE_COPY(ActionPushButton) 86 | }; 87 | 88 | #endif // ACTIONPUSHBUTTON_H 89 | -------------------------------------------------------------------------------- /src/WASimUI/widgets/BuddyLabel.h: -------------------------------------------------------------------------------- 1 | /* 2 | BuddyLabel 3 | https://github.com/mpaperno/maxLibQt 4 | 5 | COPYRIGHT: (c)2019 Maxim Paperno; All Right Reserved. 6 | Contact: http://www.WorldDesign.com/contact 7 | 8 | LICENSE: 9 | 10 | Commercial License Usage 11 | Licensees holding valid commercial licenses may use this file in 12 | accordance with the terms contained in a written agreement between 13 | you and the copyright holder. 14 | 15 | GNU General Public License Usage 16 | Alternatively, this file may be used under the terms of the GNU 17 | General Public License as published by the Free Software Foundation, 18 | either version 3 of the License, or (at your option) any later version. 19 | 20 | This program is distributed in the hope that it will be useful, 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | GNU General Public License for more details. 24 | 25 | A copy of the GNU General Public License is available at . 26 | */ 27 | 28 | #ifndef BUDDYLABEL_H 29 | #define BUDDYLABEL_H 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | /*! 39 | \brief The BuddyLabel class is a QLabel with enhanced "buddy" capabilities. 40 | 41 | It overrides the \c QLabel::setBuddy() method and, besides the usual shortcut handling provided by \c QLabel, 42 | it adds mouse click handling and mirroring of the buddy's tool tip text. 43 | 44 | Mouse clicks are connected to the \c QWidget::setFocus slot. For \c QCheckBox it also connects to the \c click() slot so the box can be (un)checked by clicking on the label. 45 | Mouse double-clicks are connected to \c QLineEdit::selectAll() on widgets which either are or have a \c QLineEdit (like \c QAbstractSpinBox and editable \c QComboBox). 46 | Custom connections could be added by connecting to the \c clicked() and/or \c doubleClicked() signals, or inheriting and overriding the \c connectBuddy() virtual method. 47 | */ 48 | class BuddyLabel : public QLabel 49 | { 50 | Q_OBJECT 51 | public: 52 | using QLabel::QLabel; 53 | 54 | public slots: 55 | //! Overrides the \c QLabel::setBuddy() method, which isn't virtual. Calls the base class implementation as well, so the shortcut mechanism still works. 56 | void setBuddy(QWidget *buddy) 57 | { 58 | if (this->buddy()) { 59 | this->buddy()->removeEventFilter(this); 60 | disconnect(this->buddy()); 61 | disconnectBuddy(this->buddy()); 62 | } 63 | 64 | QLabel::setBuddy(buddy); 65 | 66 | if (!buddy) 67 | return; 68 | 69 | setToolTip(buddy->toolTip()); 70 | buddy->installEventFilter(this); 71 | connectBuddy(buddy); 72 | } 73 | 74 | signals: 75 | //! Emitted when label is clicked with left mouse button (or something emulating one). 76 | void clicked(); 77 | //! Emitted when label is double-clicked with left mouse button (or something emulating one). 78 | void doubleClicked(); 79 | 80 | protected: 81 | //! Override this method for custom connections. 82 | virtual void connectBuddy(QWidget *buddy) 83 | { 84 | // Single clicks 85 | connect(this, &BuddyLabel::clicked, buddy, QOverload<>::of(&QWidget::setFocus)); 86 | if (QCheckBox *cb = qobject_cast(buddy)) 87 | connect(this, &BuddyLabel::clicked, cb, &QCheckBox::click); 88 | 89 | // Double clicks 90 | if (QLineEdit *le = qobject_cast(buddy)) 91 | connect(this, &BuddyLabel::doubleClicked, le, &QLineEdit::selectAll); 92 | else if (QAbstractSpinBox *sb = qobject_cast(buddy)) 93 | connect(this, &BuddyLabel::doubleClicked, sb, &QAbstractSpinBox::selectAll); 94 | else if (QComboBox *cb = qobject_cast(buddy)) 95 | if (cb->isEditable() && cb->lineEdit()) 96 | connect(this, &BuddyLabel::doubleClicked, cb->lineEdit(), &QLineEdit::selectAll); 97 | } 98 | 99 | //! Hook for custom disconnections. We already disconnect ourselves from all slots in \a buddy in the main handler. 100 | virtual void disconnectBuddy(QWidget *buddy) { Q_UNUSED(buddy) } 101 | 102 | //! The filter monitors for tool tip changes on the buddy 103 | bool eventFilter(QObject *obj, QEvent *ev) 104 | { 105 | if (ev->type() == QEvent::ToolTipChange && buddy() && obj == buddy()) 106 | setToolTip(buddy()->toolTip()); 107 | return false; 108 | } 109 | 110 | void mousePressEvent(QMouseEvent *ev) 111 | { 112 | if (ev->button() == Qt::LeftButton) { 113 | m_pressed = true; 114 | ev->accept(); 115 | } 116 | QLabel::mousePressEvent(ev); 117 | } 118 | 119 | void mouseReleaseEvent(QMouseEvent *ev) 120 | { 121 | if (m_pressed && rect().contains(ev->pos())) 122 | emit clicked(); 123 | m_pressed = false; 124 | QLabel::mouseReleaseEvent(ev); 125 | } 126 | 127 | void mouseDoubleClickEvent(QMouseEvent *ev) 128 | { 129 | if (ev->button() == Qt::LeftButton && rect().contains(ev->pos())) 130 | emit doubleClicked(); 131 | QLabel::mouseDoubleClickEvent(ev); 132 | } 133 | 134 | private: 135 | bool m_pressed = false; 136 | Q_DISABLE_COPY(BuddyLabel) 137 | }; 138 | 139 | #endif // BUDDYLABEL_H 140 | -------------------------------------------------------------------------------- /src/WASimUI/widgets/DataComboBox.h: -------------------------------------------------------------------------------- 1 | /* 2 | DataComboBox 3 | https://github.com/mpaperno/maxLibQt 4 | 5 | COPYRIGHT: (c)2019 Maxim Paperno; All Right Reserved. 6 | Contact: http://www.WorldDesign.com/contact 7 | 8 | LICENSE: 9 | 10 | Commercial License Usage 11 | Licensees holding valid commercial licenses may use this file in 12 | accordance with the terms contained in a written agreement between 13 | you and the copyright holder. 14 | 15 | GNU General Public License Usage 16 | Alternatively, this file may be used under the terms of the GNU 17 | General Public License as published by the Free Software Foundation, 18 | either version 3 of the License, or (at your option) any later version. 19 | 20 | This program is distributed in the hope that it will be useful, 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | GNU General Public License for more details. 24 | 25 | A copy of the GNU General Public License is available at . 26 | */ 27 | 28 | #ifndef _DATACOMBOBOX_H_ 29 | #define _DATACOMBOBOX_H_ 30 | 31 | #include 32 | 33 | /*! 34 | \brief The DataComboBox is a \c QComboBox with focus on the \c data() value of each item, vs. its \c index or \c text value. 35 | It adds a new \p currentData property, a \c setCurrentData() slot, and a \c currentDataChanged() signal. 36 | The default data role is \c Qt::UserRole but can be set with \c setDefaultRole(). The default data match flags for 37 | \c setCurrentData() (and the underlying \c QComboBox::findData() ) can be changed with \c setDefaultMatchFlags(). 38 | 39 | Note that the \p currentData property is set as the \c USER (default) property for this class. Some Qt parts like item view 40 | delegates may use the \c USER property. 41 | */ 42 | class DataComboBox: public QComboBox 43 | { 44 | Q_OBJECT 45 | //! Property for \c QComboBox::currentData() of the selected combo box item. \sa setCurrentData(), currentDataChanged() 46 | Q_PROPERTY(QVariant currentData READ currentData WRITE setCurrentData NOTIFY currentDataChanged USER true) 47 | //! The Role id to use for data operations unless otherwise specified. Default is \c Qt::UserRole. \sa setDefaultRole() 48 | Q_PROPERTY(int defaultRole READ defaultRole WRITE setDefaultRole) 49 | //! The default MatchFlags to use for \c setCurrentData() unless otherwise specified. \sa setDefaultMatchFlags() 50 | Q_PROPERTY(Qt::MatchFlags defaultMatchFlags READ defaultMatchFlags WRITE setDefaultMatchFlags) 51 | 52 | public: 53 | explicit DataComboBox(QWidget *parent = nullptr): 54 | QComboBox(parent) 55 | { 56 | connect(this, QOverload::of(&QComboBox::currentIndexChanged), this, &DataComboBox::onCurrentIndexChanged); 57 | } 58 | 59 | //! The Role id to use for data operations unless otherwise specified. Default is \c Qt::UserRole. \sa setDefaultRole() 60 | inline int defaultRole() const { return m_role; } 61 | //! The default MatchFlags to use for \c setCurrentData() unless otherwise specified. \sa setDefaultMatchFlags() 62 | inline Qt::MatchFlags defaultMatchFlags() const { return m_matchFlags; } 63 | 64 | //! Same as the \c QComboBox version but if \a role is \c -1 (default) then the \p defaultRole is used. 65 | inline QVariant currentData(int role = -1) const 66 | { 67 | if (role < 0) 68 | role = m_role; 69 | return QComboBox::currentData(role); 70 | } 71 | 72 | //! Adds an item like `QComboBox::addItem(const QString &, const QVariant &)` does but allows specifying the role. 73 | void addItem(const QString &text, const QVariant &data, int role) { 74 | QComboBox::addItem(text); 75 | setItemData(count() - 1, data, role); 76 | } 77 | 78 | //! Add items with names from \a texts, with corresponding data from \a datas list, using the specified \a role. If \a role is \c -1 (default) then the \p defaultRole is used. 79 | void addItems(const QStringList &texts, const QVariantList &datas, int role = -1) 80 | { 81 | if (role < 0) 82 | role = m_role; 83 | for (int i=0; i < texts.count(); ++i) 84 | addItem(texts.at(i), datas.value(i, texts.at(i)), role); 85 | } 86 | 87 | //! Add items with corresponding data from \a items map, using the specified \a role. If \a role is \c -1 (default) then the \p defaultRole is used. 88 | void addItems(const QMap &items, int role = -1) { 89 | addItems(items.keys(), items.values(), role); 90 | } 91 | 92 | //! Add items with names from \a texts, with corresponding data from \a datas list, using the specified \a role. If \a role is \c -1 (default) then the \p defaultRole is used. 93 | void addItems(const QStringList &texts, const QStringList &datas, int role = -1) 94 | { 95 | if (role < 0) 96 | role = m_role; 97 | for (int i=0; i < texts.count(); ++i) 98 | addItem(texts.at(i), datas.value(i, texts.at(i)), role); 99 | } 100 | 101 | //! Add items with corresponding data from \a items map, using the specified \a role. If \a role is \c -1 (default) then the \p defaultRole is used. 102 | void addItems(const QMap &items, int role = -1) { 103 | addItems(items.keys(), items.values(), role); 104 | } 105 | 106 | // bring back the superclass versions 107 | using QComboBox::addItem; 108 | using QComboBox::addItems; 109 | 110 | public slots: 111 | //! Convenience slot for \c QComboBox::setCurrentIndex(findData(value, role, matchFlags)) 112 | //! If \a role is \c -1 (default) then the \p defaultRole is used. If \a matchFlags is \c -1 (default) then the \p defaultMatchFlags are used. 113 | inline void setCurrentData(const QVariant &value, int role = -1, int matchFlags = -1) 114 | { 115 | if (role < 0) 116 | role = m_role; 117 | if (matchFlags < 0) 118 | matchFlags = m_matchFlags; 119 | setCurrentIndex(findData(value, role, Qt::MatchFlags(matchFlags))); 120 | } 121 | 122 | //! Set the Role id to use for data operations unless otherwise specified. Default is \c Qt::UserRole. \sa defaultRole() 123 | inline void setDefaultRole(int role) { m_role = role; } 124 | //! Set the default \c Qt::MatchFlags to use for \c setCurrentData() to \a flags. Default is \c {Qt::MatchExactly | Qt::MatchCaseSensitive} (same as \c QComboBox::findData() ). \sa defaultMatchFlags() 125 | inline void setDefaultMatchFlags(Qt::MatchFlags flags) { m_matchFlags = flags; } 126 | 127 | signals: 128 | //! Emitted whenever the \p currentIndex changes. The \a value is in the current \p defaultRole (\c Qt::UserRole unless set otherwise with \c setDefaultRole() ) 129 | void currentDataChanged(const QVariant &value); 130 | 131 | protected slots: 132 | void onCurrentIndexChanged(int) 133 | { 134 | emit currentDataChanged(currentData(m_role)); 135 | } 136 | 137 | protected: 138 | int m_role = Qt::UserRole; 139 | Qt::MatchFlags m_matchFlags = Qt::MatchExactly | Qt::MatchCaseSensitive; 140 | }; 141 | 142 | #endif // _DATACOMBOBOX_H_ 143 | -------------------------------------------------------------------------------- /src/WASimUI/widgets/FilterLineEdit.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | Original version from ; Used under GPL v3 license; Modifications applied. 6 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 7 | 8 | This file may be used under the terms of the GNU General Public License (GPL) 9 | as published by the Free Software Foundation, either version 3 of the Licenses, 10 | or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | A copy of the GNU GPL is included with this project 18 | and is also available at . 19 | */ 20 | 21 | #include "FilterLineEdit.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | FilterLineEdit::FilterLineEdit(QWidget* parent, std::vector* filters, int columnnum) : 29 | QLineEdit(parent), 30 | filterList(filters), 31 | columnNumber(columnnum) 32 | { 33 | setPlaceholderText(tr("Filter")); 34 | setClearButtonEnabled(true); 35 | setProperty("column", columnnum); // Store the column number for later use 36 | 37 | // Introduce a timer for delaying the signal triggered whenever the user changes the filter value. 38 | // The idea here is that the textChanged() event isn't connected to the update filter slot directly anymore 39 | // but instead there this timer mechanism in between: whenever the user changes the filter the delay timer 40 | // is (re)started. As soon as the user stops typing the timer has a chance to trigger and call the 41 | // delayedSignalTimerTriggered() method which then stops the timer and emits the delayed signal. 42 | delaySignalTimer = new QTimer(this); 43 | delaySignalTimer->setInterval(200); // This is the milliseconds of not-typing we want to wait before triggering 44 | connect(this, &FilterLineEdit::textChanged, delaySignalTimer, QOverload<>::of(&QTimer::start)); 45 | connect(delaySignalTimer, &QTimer::timeout, this, &FilterLineEdit::delayedSignalTimerTriggered); 46 | 47 | const QString help(tr( 48 | "

These input fields allow you to perform quick filters in the currently selected table.

" 49 | "All filters are case-insensitive. By default a search is performed anywhere in the column's value (*text*).
" 50 | "The following operators are also supported:
" 51 | "" 52 | "" 53 | "" 54 | "" 55 | "" 56 | "" 57 | "
*Matches zero or more of any characters.
?Matches any single character.
\\* or \\?Matches a literal asterisk or question mark (\"escapes\" it).
[...]Sets of characters can be represented in square brackets, similar to full regular expressions.
/regexp/Values matching the regular expression between the slashes (/).
" 58 | )); 59 | 60 | setToolTip(help); 61 | setWhatsThis(help); 62 | 63 | // Immediately emit the delayed filter value changed signal if the user presses the enter or the return key or 64 | // the line edit widget loses focus 65 | connect(this, &FilterLineEdit::editingFinished, this, &FilterLineEdit::delayedSignalTimerTriggered); 66 | 67 | // Prepare for adding the What's This information and filter helper actions to the context menu 68 | setContextMenuPolicy(Qt::CustomContextMenu); 69 | connect(this, &FilterLineEdit::customContextMenuRequested, this, &FilterLineEdit::showContextMenu); 70 | } 71 | 72 | void FilterLineEdit::delayedSignalTimerTriggered() 73 | { 74 | // Stop the timer first to avoid triggering in intervals 75 | delaySignalTimer->stop(); 76 | 77 | // Only emit text changed signal if the text has actually changed in comparison to the last emitted signal. This is necessary 78 | // because this method is also called whenever the line edit loses focus and not only when its text has definitely been changed. 79 | if(text() != lastValue) 80 | { 81 | // Emit the delayed signal using the current value 82 | emit delayedTextChanged(columnNumber, text()); 83 | 84 | // Remember this value for the next time 85 | lastValue = text(); 86 | } 87 | } 88 | 89 | void FilterLineEdit::keyReleaseEvent(QKeyEvent* event) 90 | { 91 | if (filterList) { 92 | if (event->key() == Qt::Key_Tab) { 93 | if (columnNumber < filterList->size() - 1) 94 | filterList->at((size_t)columnNumber + 1)->setFocus(); 95 | else 96 | filterList->at(0)->setFocus(); 97 | return; 98 | } 99 | else if (event->key() == Qt::Key_Backtab && columnNumber > 0) { 100 | filterList->at((size_t)columnNumber - 1)->setFocus(); 101 | return; 102 | } 103 | } 104 | 105 | QLineEdit::keyReleaseEvent(event); 106 | } 107 | 108 | void FilterLineEdit::focusInEvent(QFocusEvent* event) 109 | { 110 | QLineEdit::focusInEvent(event); 111 | emit filterFocused(); 112 | } 113 | 114 | void FilterLineEdit::clear() 115 | { 116 | // When programmatically clearing the line edit's value make sure the effects are applied immediately, i.e. 117 | // bypass the delayed signal timer 118 | QLineEdit::clear(); 119 | delayedSignalTimerTriggered(); 120 | } 121 | 122 | void FilterLineEdit::setText(const QString& text) 123 | { 124 | // When programmatically setting the line edit's value make sure the effects are applied immediately, i.e. 125 | // bypass the delayed signal timer 126 | QLineEdit::setText(text); 127 | delayedSignalTimerTriggered(); 128 | } 129 | 130 | void FilterLineEdit::setFilterHelper(const QString& filterOperator, const QString& operatorSuffix, bool clearCurrent) 131 | { 132 | const QString txt(clearCurrent ? "" : text()); 133 | setText(txt + filterOperator + "?" + operatorSuffix); 134 | // Select the value for easy editing of the expression 135 | setSelection(filterOperator.length() + txt.length(), 1); 136 | } 137 | 138 | void FilterLineEdit::showContextMenu(const QPoint &pos) 139 | { 140 | 141 | // This has to be created here, otherwise the set of enabled options would not update accordingly. 142 | QMenu* editContextMenu = createStandardContextMenu(); 143 | editContextMenu->addSeparator(); 144 | 145 | QMenu* filterMenu = editContextMenu->addMenu(tr("Set Filter Expression")); 146 | 147 | filterMenu->addAction(QIcon("help_outline.glyph"), tr("What's This?"), this, [&]() { 148 | QWhatsThis::showText(pos, whatsThis(), this); 149 | }); 150 | filterMenu->addSeparator(); 151 | filterMenu->addAction(tr("Starts with..."), this, [&]() { setFilterHelper(QString (""), QString("*")); }); 152 | filterMenu->addAction(tr("... ends with"), this, [&]() { setFilterHelper(QString ("*"), QString(""), false); }); 153 | filterMenu->addAction(tr("In range [...]"), this, [&]() { setFilterHelper(QString ("["), QString("]")); }); 154 | filterMenu->addAction(tr("Regular expression..."), this, [&]() { setFilterHelper(QString ("/"), QString ("/")); }); 155 | 156 | editContextMenu->exec(mapToGlobal(pos)); 157 | } 158 | -------------------------------------------------------------------------------- /src/WASimUI/widgets/FilterLineEdit.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | Original version from ; Used under GPL v3 license; Modifications applied. 6 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 7 | 8 | This file may be used under the terms of the GNU General Public License (GPL) 9 | as published by the Free Software Foundation, either version 3 of the Licenses, 10 | or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | A copy of the GNU GPL is included with this project 18 | and is also available at . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | class QTimer; 27 | class QKeyEvent; 28 | 29 | class FilterLineEdit : public QLineEdit 30 | { 31 | Q_OBJECT 32 | 33 | public: 34 | explicit FilterLineEdit(QWidget* parent, std::vector* filters = nullptr, int columnnum = 0); 35 | 36 | // Override methods for programmatically changing the value of the line edit 37 | void clear(); 38 | void setText(const QString& text); 39 | 40 | Q_SIGNALS: 41 | void delayedTextChanged(int column, QString text); 42 | void filterFocused(); 43 | 44 | protected: 45 | void keyReleaseEvent(QKeyEvent* event) override; 46 | void focusInEvent(QFocusEvent* event) override; 47 | 48 | private Q_SLOTS: 49 | void delayedSignalTimerTriggered(); 50 | void setFilterHelper(const QString& filterOperator, const QString& operatorSuffix = QString(), bool clearCurrent = true); 51 | void showContextMenu(const QPoint &pos); 52 | 53 | private: 54 | std::vector* filterList; 55 | int columnNumber; 56 | QTimer* delaySignalTimer; 57 | QString lastValue; 58 | 59 | }; 60 | -------------------------------------------------------------------------------- /src/WASimUI/widgets/FilterTableHeader.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | Original version from ; Used under GPL v3 license; Modifications applied. 6 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 7 | 8 | This file may be used under the terms of the GNU General Public License (GPL) 9 | as published by the Free Software Foundation, either version 3 of the Licenses, 10 | or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | A copy of the GNU GPL is included with this project 18 | and is also available at . 19 | */ 20 | 21 | #include "FilterTableHeader.h" 22 | #include "FilterLineEdit.h" 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | FilterTableHeader::FilterTableHeader(QTableView* parent) : 29 | QHeaderView(Qt::Horizontal, parent) 30 | { 31 | // Do some connects: Basically just resize and reposition the input widgets whenever anything changes 32 | connect(this, &FilterTableHeader::sectionResized, this, &FilterTableHeader::adjustPositions); 33 | connect(this, &FilterTableHeader::sectionClicked, this, &FilterTableHeader::adjustPositions); 34 | connect(parent->horizontalScrollBar(), &QScrollBar::valueChanged, this, &FilterTableHeader::adjustPositions); 35 | connect(parent->verticalScrollBar(), &QScrollBar::valueChanged, this, &FilterTableHeader::adjustPositions); 36 | } 37 | 38 | void FilterTableHeader::generateFilters(int number) 39 | { 40 | // Delete all the current filter widgets 41 | qDeleteAll(filterWidgets); 42 | filterWidgets.clear(); 43 | 44 | // And generate a bunch of new ones 45 | for(int i=0; i < number; ++i) 46 | { 47 | FilterLineEdit* l = new FilterLineEdit(this, &filterWidgets, i); 48 | l->setVisible(m_filtersVisible); 49 | // Set as focus proxy the first non-row-id visible filter-line. 50 | if(!i) 51 | setFocusProxy(l); 52 | connect(l, &FilterLineEdit::delayedTextChanged, this, &FilterTableHeader::inputChanged); 53 | connect(l, &FilterLineEdit::filterFocused, this, &FilterTableHeader::filterFocused); 54 | filterWidgets.push_back(l); 55 | } 56 | 57 | // Position them correctly 58 | updateGeometries(); 59 | } 60 | 61 | QSize FilterTableHeader::sizeHint() const 62 | { 63 | // For the size hint just take the value of the standard implementation and add the height of a input widget to it if necessary 64 | QSize s = QHeaderView::sizeHint(); 65 | if(m_filtersVisible && filterWidgets.size()) 66 | s.setHeight(s.height() + filterWidgets.at(0)->sizeHint().height() + 4); // The 4 adds just adds some extra space 67 | return s; 68 | } 69 | 70 | void FilterTableHeader::updateGeometries() 71 | { 72 | // If there are any input widgets add a viewport margin to the header to generate some empty space for them which is not affected by scrolling 73 | if(m_filtersVisible && filterWidgets.size()) 74 | setViewportMargins(0, 0, 0, filterWidgets.at(0)->sizeHint().height()); 75 | else 76 | setViewportMargins(0, 0, 0, 0); 77 | 78 | // Now just call the parent implementation and reposition the input widgets 79 | QHeaderView::updateGeometries(); 80 | adjustPositions(); 81 | } 82 | 83 | void FilterTableHeader::adjustPositions() 84 | { 85 | // The two adds some extra space between the header label and the input widget 86 | const int y = QHeaderView::sizeHint().height() + 2; 87 | // Loop through all widgets 88 | for(int i=0, e = (int)filterWidgets.size(); i < e; ++i) { 89 | // Get the current widget, move it and resize it 90 | QWidget* w = filterWidgets.at((size_t)i); 91 | if (QApplication::layoutDirection() == Qt::RightToLeft) 92 | w->move(width() - (sectionPosition(i) + sectionSize(i) - offset()), y); 93 | else 94 | w->move(sectionPosition(i) - offset(), y); 95 | w->resize(sectionSize(i), w->sizeHint().height()); 96 | } 97 | } 98 | 99 | void FilterTableHeader::inputChanged(int col, const QString& new_value) 100 | { 101 | //adjustPositions(); 102 | // Just get the column number and the new value and send them to anybody interested in filter changes 103 | emit filterChanged(col, new_value); 104 | } 105 | 106 | void FilterTableHeader::clearFilters() 107 | { 108 | for(FilterLineEdit* filterLineEdit : filterWidgets) 109 | filterLineEdit->clear(); 110 | } 111 | 112 | void FilterTableHeader::setFilter(int column, const QString& value) 113 | { 114 | if(column < filterWidgets.size()) 115 | filterWidgets.at(column)->setText(value); 116 | } 117 | 118 | QString FilterTableHeader::filterValue(int column) const 119 | { 120 | return filterWidgets[column]->text(); 121 | } 122 | 123 | void FilterTableHeader::setFocusColumn(int column) 124 | { 125 | if(column < filterWidgets.size()) 126 | filterWidgets.at(column)->setFocus(Qt::FocusReason::TabFocusReason); 127 | } 128 | 129 | void FilterTableHeader::setFiltersVisible(bool visible) 130 | { 131 | if (m_filtersVisible == visible) 132 | return; 133 | m_filtersVisible = visible; 134 | for(FilterLineEdit* filterLineEdit : filterWidgets) 135 | filterLineEdit->setVisible(visible); 136 | if (!visible) 137 | clearFilters(); 138 | updateGeometries(); 139 | } 140 | -------------------------------------------------------------------------------- /src/WASimUI/widgets/FilterTableHeader.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | Original version from ; Used under GPL v3 license; Modifications applied. 6 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 7 | 8 | This file may be used under the terms of the GNU General Public License (GPL) 9 | as published by the Free Software Foundation, either version 3 of the Licenses, 10 | or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | A copy of the GNU GPL is included with this project 18 | and is also available at . 19 | */ 20 | 21 | #ifndef FILTERTABLEHEADER_H 22 | #define FILTERTABLEHEADER_H 23 | 24 | #include 25 | #include 26 | 27 | class QTableView; 28 | class FilterLineEdit; 29 | 30 | class FilterTableHeader : public QHeaderView 31 | { 32 | Q_OBJECT 33 | 34 | public: 35 | explicit FilterTableHeader(QTableView* parent = nullptr); 36 | QSize sizeHint() const override; 37 | bool hasFilters() const { return (filterWidgets.size() > 0); } 38 | bool areFiltersVisible() const { return m_filtersVisible; } 39 | QString filterValue(int column) const; 40 | 41 | public Q_SLOTS: 42 | void generateFilters(int number); 43 | void adjustPositions(); 44 | void clearFilters(); 45 | void setFilter(int column, const QString& value); 46 | void setFocusColumn(int column); 47 | void setFiltersVisible(bool visible = true); 48 | 49 | Q_SIGNALS: 50 | void filterChanged(int column, QString value); 51 | void filterFocused(); 52 | 53 | protected: 54 | void updateGeometries() override; 55 | 56 | private Q_SLOTS: 57 | void inputChanged(int col, const QString& new_value); 58 | 59 | private: 60 | std::vector filterWidgets {}; 61 | bool m_filtersVisible = false; 62 | }; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /src/WASimUI/widgets/MultisortTableView.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | Original version from ; Used under GPL v3 license; Modifications applied. 6 | 7 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 8 | 9 | This file may be used under the terms of the GNU General Public License (GPL) 10 | as published by the Free Software Foundation, either version 3 of the Licenses, 11 | or (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | A copy of the GNU GPL is included with this project 19 | and is also available at . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "MultiColumnProxyModel.h" 30 | 31 | class MultisortTableView : public QTableView 32 | { 33 | Q_OBJECT 34 | public: 35 | explicit MultisortTableView(QWidget *parent = 0) : 36 | QTableView(parent), 37 | m_isSortingEnabled(false), 38 | m_proxyModel(new MultiColumnProxyModel(this)), 39 | m_modifier(Qt::ControlModifier) 40 | { 41 | QTableView::setSortingEnabled(false); // we do our own sorting 42 | setupHeader(); 43 | } 44 | 45 | /// Overrides parent method for internal handling of sorting state. 46 | bool isSortingEnabled() const { return m_isSortingEnabled; } 47 | /// Returns the custom proxy model used for sorting and filtering. 48 | MultiColumnProxyModel *proxyModel() const { return m_proxyModel; } 49 | /// Returns the original source model. 50 | QAbstractItemModel *sourceModel() const { return m_proxyModel->sourceModel(); } 51 | 52 | virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const { return m_proxyModel->mapToSource(proxyIndex); } 53 | virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const { return m_proxyModel->mapFromSource(sourceIndex); } 54 | virtual QItemSelection mapSelectionToSource(const QItemSelection &proxySelection) const { return m_proxyModel->mapSelectionToSource(proxySelection); } 55 | virtual QItemSelection mapSelectionFromSource(const QItemSelection &sourceSelection) const { return m_proxyModel->mapSelectionFromSource(sourceSelection); } 56 | 57 | bool hasSelection() const { return selectionModel()->hasSelection(); } 58 | QItemSelection selection() const { mapSelectionToSource(selectionModel()->selection()); } 59 | 60 | QModelIndexList selectedRows(int column = 0) const 61 | { 62 | QModelIndexList sel = selectionModel()->selectedRows(column); 63 | for (QModelIndex &i : sel) 64 | i = mapToSource(i); 65 | return sel; 66 | } 67 | 68 | public Q_SLOTS: 69 | /// Set key modifier to handle multicolumn sorting. 70 | void setModifier(Qt::KeyboardModifier modifier) { m_modifier = modifier; } 71 | 72 | /// Overrides parent method for internal handling of sorting state. 73 | void setSortingEnabled(bool enable) { 74 | m_isSortingEnabled = enable; 75 | if (enable) 76 | m_proxyModel->sortColumn(horizontalHeader()->sortIndicatorSection(), false, (qint8)horizontalHeader()->sortIndicatorOrder()); 77 | } 78 | 79 | virtual void setStringFilter(int col, QString pattern, int role = Qt::DisplayRole) { 80 | m_proxyModel->setStringPatternFilter(col, pattern, role); 81 | } 82 | 83 | virtual void setDisplayRoleStringFilter(int col, QString pattern) { 84 | m_proxyModel->setStringPatternFilter(col, pattern, Qt::DisplayRole); 85 | } 86 | 87 | virtual void setRegExpFilter(int col, const QRegExp& pattern, int role = Qt::DisplayRole) { 88 | m_proxyModel->setRegExpFilter(col, pattern, Qt::DisplayRole); 89 | } 90 | 91 | /// Overrides parent method for hooking into header's clicked signal and remove default sort indicator. 92 | virtual void setHorizontalHeader(QHeaderView *hdr) { 93 | QTableView::setHorizontalHeader(hdr); 94 | setupHeader(); 95 | } 96 | 97 | /// Overridden to use custom sorting model; 98 | virtual void setModel(QAbstractItemModel *model) { 99 | m_proxyModel->setSourceModel(model); 100 | QTableView::setModel(m_proxyModel); 101 | } 102 | 103 | private Q_SLOTS: 104 | void onHeaderSectionrClicked(int column) { 105 | if (m_isSortingEnabled) 106 | m_proxyModel->sortColumn(column, (QApplication::keyboardModifiers() & m_modifier)); 107 | //qDebug() << column << (Qt::SortOrder)m_proxyModel->columnSortOrder(column); 108 | } 109 | void onSortIndicatorChanged(int column, Qt::SortOrder order) { 110 | //if (m_isSortingEnabled) 111 | //m_proxyModel->sortColumn(column, (QApplication::keyboardModifiers() & m_modifier), (qint8)order); 112 | //qDebug() << column << horizontalHeader()->sortIndicatorSection() << horizontalHeader()->sortIndicatorOrder(); 113 | } 114 | 115 | void setupHeader() { 116 | horizontalHeader()->setSortIndicatorShown(false); // we provide our own indicators 117 | horizontalHeader()->setSectionsClickable(true); // make sure to receive click events so we can sort 118 | connect(horizontalHeader(), &QHeaderView::sectionClicked, this, &MultisortTableView::onHeaderSectionrClicked); 119 | //connect(horizontalHeader(), &QHeaderView::sortIndicatorChanged, this, &MultisortTableView::onSortIndicatorChanged); 120 | } 121 | 122 | private: 123 | // Sorting enable state 124 | bool m_isSortingEnabled; 125 | // ProxyModel to sorting columns 126 | MultiColumnProxyModel *m_proxyModel; 127 | // Modifier to handle multicolumn sorting 128 | Qt::KeyboardModifier m_modifier; 129 | 130 | }; 131 | -------------------------------------------------------------------------------- /src/common.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <_PropertySheetDisplayName>common 7 | $(SolutionDir)include;$(IncludePath) 8 | $(SolutionDir)build\$(ProjectName)\$(Configuration)-$(Platform)\ 9 | $(SolutionDir)build\$(ProjectName)\obj\$(Configuration)-$(Platform)\ 10 | 11 | 12 | 13 | _$(OutputType);_MBCS;%(PreprocessorDefinitions) 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/include/LICENSE.LGPL.txt: -------------------------------------------------------------------------------- 1 | 2 | GNU LESSER GENERAL PUBLIC LICENSE 3 | Version 3, 29 June 2007 4 | 5 | Copyright (C) 2007 Free Software Foundation, Inc. 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | 10 | This version of the GNU Lesser General Public License incorporates 11 | the terms and conditions of version 3 of the GNU General Public 12 | License, supplemented by the additional permissions listed below. 13 | 14 | 0. Additional Definitions. 15 | 16 | As used herein, "this License" refers to version 3 of the GNU Lesser 17 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 18 | General Public License. 19 | 20 | "The Library" refers to a covered work governed by this License, 21 | other than an Application or a Combined Work as defined below. 22 | 23 | An "Application" is any work that makes use of an interface provided 24 | by the Library, but which is not otherwise based on the Library. 25 | Defining a subclass of a class defined by the Library is deemed a mode 26 | of using an interface provided by the Library. 27 | 28 | A "Combined Work" is a work produced by combining or linking an 29 | Application with the Library. The particular version of the Library 30 | with which the Combined Work was made is also called the "Linked 31 | Version". 32 | 33 | The "Minimal Corresponding Source" for a Combined Work means the 34 | Corresponding Source for the Combined Work, excluding any source code 35 | for portions of the Combined Work that, considered in isolation, are 36 | based on the Application, and not on the Linked Version. 37 | 38 | The "Corresponding Application Code" for a Combined Work means the 39 | object code and/or source code for the Application, including any data 40 | and utility programs needed for reproducing the Combined Work from the 41 | Application, but excluding the System Libraries of the Combined Work. 42 | 43 | 1. Exception to Section 3 of the GNU GPL. 44 | 45 | You may convey a covered work under sections 3 and 4 of this License 46 | without being bound by section 3 of the GNU GPL. 47 | 48 | 2. Conveying Modified Versions. 49 | 50 | If you modify a copy of the Library, and, in your modifications, a 51 | facility refers to a function or data to be supplied by an Application 52 | that uses the facility (other than as an argument passed when the 53 | facility is invoked), then you may convey a copy of the modified 54 | version: 55 | 56 | a) under this License, provided that you make a good faith effort to 57 | ensure that, in the event an Application does not supply the 58 | function or data, the facility still operates, and performs 59 | whatever part of its purpose remains meaningful, or 60 | 61 | b) under the GNU GPL, with none of the additional permissions of 62 | this License applicable to that copy. 63 | 64 | 3. Object Code Incorporating Material from Library Header Files. 65 | 66 | The object code form of an Application may incorporate material from 67 | a header file that is part of the Library. You may convey such object 68 | code under terms of your choice, provided that, if the incorporated 69 | material is not limited to numerical parameters, data structure 70 | layouts and accessors, or small macros, inline functions and templates 71 | (ten or fewer lines in length), you do both of the following: 72 | 73 | a) Give prominent notice with each copy of the object code that the 74 | Library is used in it and that the Library and its use are 75 | covered by this License. 76 | 77 | b) Accompany the object code with a copy of the GNU GPL and this license 78 | document. 79 | 80 | 4. Combined Works. 81 | 82 | You may convey a Combined Work under terms of your choice that, 83 | taken together, effectively do not restrict modification of the 84 | portions of the Library contained in the Combined Work and reverse 85 | engineering for debugging such modifications, if you also do each of 86 | the following: 87 | 88 | a) Give prominent notice with each copy of the Combined Work that 89 | the Library is used in it and that the Library and its use are 90 | covered by this License. 91 | 92 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 93 | document. 94 | 95 | c) For a Combined Work that displays copyright notices during 96 | execution, include the copyright notice for the Library among 97 | these notices, as well as a reference directing the user to the 98 | copies of the GNU GPL and this license document. 99 | 100 | d) Do one of the following: 101 | 102 | 0) Convey the Minimal Corresponding Source under the terms of this 103 | License, and the Corresponding Application Code in a form 104 | suitable for, and under terms that permit, the user to 105 | recombine or relink the Application with a modified version of 106 | the Linked Version to produce a modified Combined Work, in the 107 | manner specified by section 6 of the GNU GPL for conveying 108 | Corresponding Source. 109 | 110 | 1) Use a suitable shared library mechanism for linking with the 111 | Library. A suitable mechanism is one that (a) uses at run time 112 | a copy of the Library already present on the user's computer 113 | system, and (b) will operate properly with a modified version 114 | of the Library that is interface-compatible with the Linked 115 | Version. 116 | 117 | e) Provide Installation Information, but only if you would otherwise 118 | be required to provide such information under section 6 of the 119 | GNU GPL, and only to the extent that such information is 120 | necessary to install and execute a modified version of the 121 | Combined Work produced by recombining or relinking the 122 | Application with a modified version of the Linked Version. (If 123 | you use option 4d0, the Installation Information must accompany 124 | the Minimal Corresponding Source and Corresponding Application 125 | Code. If you use option 4d1, you must provide the Installation 126 | Information in the manner specified by section 6 of the GNU GPL 127 | for conveying Corresponding Source.) 128 | 129 | 5. Combined Libraries. 130 | 131 | You may place library facilities that are a work based on the 132 | Library side by side in a single library together with other library 133 | facilities that are not Applications and are not covered by this 134 | License, and convey such a combined library under terms of your 135 | choice, if you do both of the following: 136 | 137 | a) Accompany the combined library with a copy of the same work based 138 | on the Library, uncombined with any other library facilities, 139 | conveyed under the terms of this License. 140 | 141 | b) Give prominent notice with the combined library that part of it 142 | is a work based on the Library, and explaining where to find the 143 | accompanying uncombined form of the same work. 144 | 145 | 6. Revised Versions of the GNU Lesser General Public License. 146 | 147 | The Free Software Foundation may publish revised and/or new versions 148 | of the GNU Lesser General Public License from time to time. Such new 149 | versions will be similar in spirit to the present version, but may 150 | differ in detail to address new problems or concerns. 151 | 152 | Each version is given a distinguishing version number. If the 153 | Library as you received it specifies that a certain numbered version 154 | of the GNU Lesser General Public License "or any later version" 155 | applies to it, you have the option of following the terms and 156 | conditions either of that published version or of any later version 157 | published by the Free Software Foundation. If the Library as you 158 | received it does not specify a version number of the GNU Lesser 159 | General Public License, you may choose any version of the GNU Lesser 160 | General Public License ever published by the Free Software Foundation. 161 | 162 | If the Library as you received it specifies that a proxy can decide 163 | whether future versions of the GNU Lesser General Public License shall 164 | apply, that proxy's public statement of acceptance of any version is 165 | permanent authorization for you to choose that version for the 166 | Library. 167 | -------------------------------------------------------------------------------- /src/include/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | WASimCommander Project 3 | WASim API Definitions and Client Components 4 | 5 | COPYRIGHT: Maxim Paperno; All Rights Reserved. 6 | 7 | Dual licensed under the terms of either the GNU General Public License (**GPL**) 8 | or the GNU Lesser General Public License (**LGPL**), as published by the Free Software 9 | Foundation, either **version 3** of the Licenses, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Copies of the GNU GPL and LGPL are included with this project 17 | in the files named LICENSE.GPL.txt and LICENSE.LGPL.txt respectively, 18 | and are available at . 19 | 20 | Except as contained in this copyright notice, the names of the authors or 21 | their institutions shall not be used in advertising or otherwise to 22 | promote the sale, use, or other dealings in, any product using this 23 | Software, or any derivative of this Software, without prior written 24 | authorization from the authors. 25 | 26 | This project may also use 3rd-party Open Source software under the terms 27 | of their respective licenses. The copyright notice above does not apply 28 | to any 3rd-party components used within. 29 | -------------------------------------------------------------------------------- /src/include/README.md: -------------------------------------------------------------------------------- 1 | # WASimCommander 2 | ## WASim API Definitions and Client Components 3 | 4 | This directory contains the necessary header files for using the `WASimClient` library or 5 | building a custom client for direct WASimModule (Server) interaction using `WASimAPI`. 6 | 7 | The API is designed to be intergrated as part of either a static or dynamic library into other software. 8 | `WASimClient` is one such implementation, and is available in both static and dynamic forms. 9 | To encourage adaptation, both are dual licensed under the terms of the GPL or LGPL (see LICENSE.txt for details). 10 | -------------------------------------------------------------------------------- /src/include/client/enums.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of either the GNU General Public License (GPL) 8 | or the GNU Lesser General Public License (LGPL), as published by the Free Software 9 | Foundation, either version 3 of the Licenses, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Copies of the GNU GPL and LGPL are included with this project 17 | and are available at . 18 | */ 19 | 20 | #pragma once 21 | 22 | #ifdef WSMCMND_ENUM_EXPORT 23 | #undef WSMCMND_ENUM_EXPORT 24 | #undef WSMCMND_ENUM_NAMESPACE 25 | #endif 26 | 27 | #define WSMCMND_ENUM_EXPORT 28 | #define WSMCMND_ENUM_NAMESPACE WASimCommander::Client 29 | 30 | #include "./enums_impl.h" 31 | -------------------------------------------------------------------------------- /src/include/client/enums_impl.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of either the GNU General Public License (GPL) 8 | or the GNU Lesser General Public License (LGPL), as published by the Free Software 9 | Foundation, either version 3 of the Licenses, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Copies of the GNU GPL and LGPL are included with this project 17 | and are available at . 18 | */ 19 | 20 | // DO NOT USE THIS FILE DIRECTLY -- NO INCLUDE GUARD 21 | // Use client/enums.h 22 | 23 | #include 24 | #include 25 | 26 | #ifndef WSMCMND_ENUM_EXPORT 27 | #define WSMCMND_ENUM_EXPORT 28 | #define WSMCMND_ENUM_NAMESPACE WASimCommander::Client 29 | #endif 30 | 31 | namespace WSMCMND_ENUM_NAMESPACE 32 | { 33 | 34 | /// Client status flags. \sa WASimClient::status() 35 | WSMCMND_ENUM_EXPORT enum class ClientStatus : uint8_t 36 | { 37 | Idle = 0x00, ///< no active SimConnect or WASim server connection 38 | Initializing = 0x01, ///< trying to connect to SimConnect 39 | SimConnected = 0x02, ///< have SimConnect link 40 | Connecting = 0x04, ///< attempting connection to WASim server 41 | Connected = 0x08, ///< connected to WASim server 42 | ShuttingDown = 0x10, ///< closing SimConnect link, before being back in Idle status mode 43 | AllConnected = SimConnected | Connected, 44 | }; 45 | #if defined(DEFINE_ENUM_FLAG_OPERATORS) && !defined(_MANAGED) 46 | DEFINE_ENUM_FLAG_OPERATORS(ClientStatus) 47 | #endif 48 | /// \name Enumeration name strings 49 | /// \{ 50 | static const std::vector ClientStatusNames = { "Idle", "Initializing", "SimConnected", "Connecting", "Connected", "ShuttingDown" }; ///< \refwcc{ClientStatus} enum names. 51 | /// \} 52 | 53 | /// Client event type enumeration. \sa ClientEvent, ClientStatus, WASimClient::setClientEventCallback() 54 | WSMCMND_ENUM_EXPORT enum class ClientEventType : uint8_t 55 | { 56 | None = 0, 57 | SimConnecting, ///< Initializing status 58 | SimConnected, ///< SimConnected status 59 | SimDisconnecting, ///< ShuttingDown status 60 | SimDisconnected, ///< From SimConnected to Initializing status change 61 | ServerConnecting, ///< Connecting status 62 | ServerConnected, ///< Connected status 63 | ServerDisconnected, ///< From Connected to SimConnected status change 64 | }; 65 | /// \name Enumeration name strings 66 | /// \{ 67 | static const std::vector ClientEventTypeNames = { "None", 68 | "SimConnecting", "SimConnected", "SimDisconnecting", "SimDisconnected", 69 | "ServerConnecting", "ServerConnected", "ServerDisconnected" }; ///< \refwcc{ClientEventType} enum names. 70 | /// \} 71 | 72 | /// Log entry source, Client or Server. \sa WASimClient::logCallback_t 73 | WSMCMND_ENUM_EXPORT enum class LogSource : uint8_t 74 | { 75 | Client, ///< Log record from WASimClient 76 | Server ///< Log record from WASimModule (Server) 77 | }; 78 | /// \name Enumeration name strings 79 | /// \{ 80 | static const std::vector LogSourceNames = { "Client", "Server" }; ///< \refwcc{LogSource} enum names. 81 | /// \} 82 | 83 | }; 84 | -------------------------------------------------------------------------------- /src/include/client/exports.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of either the GNU General Public License (GPL) 8 | or the GNU Lesser General Public License (LGPL), as published by the Free Software 9 | Foundation, either version 3 of the Licenses, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Copies of the GNU GPL and LGPL are included with this project 17 | and are available at . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "global.h" 23 | 24 | #if defined(_MSC_VER) && defined(WSMCMND_API_IMPORT) 25 | 26 | // This exercise is mainly to silence MSVC warnings (C4251) when exporting (to DLL) some variables which use stdlib templated types. 27 | // It does not actually make any difference since the produced DLLs are compiler-specific anyway. And we're only exporting 28 | // very basic vector types which are simply dynamic memory allocation (std::string just being a glorified char array, after all). 29 | // We could probably just as well disable the warning... but we'll try to do it "the right way." 30 | //#pragma warning( disable: 4251 ) 31 | 32 | #include 33 | #include 34 | 35 | // for string (basic_string) 36 | WSMCMND_API_IMPORT template class WSMCMND_API std::allocator; 37 | WSMCMND_API_IMPORT template union WSMCMND_API std::_String_val>::_Bxty; 38 | WSMCMND_API_IMPORT template class WSMCMND_API std::_String_val>; 39 | WSMCMND_API_IMPORT template class WSMCMND_API std::_Compressed_pair,std::_String_val>,true>; 40 | WSMCMND_API_IMPORT template class WSMCMND_API std::basic_string, std::allocator>; 41 | // for vector 42 | WSMCMND_API_IMPORT template class WSMCMND_API std::allocator; 43 | WSMCMND_API_IMPORT template class WSMCMND_API std::_Vector_val>; 44 | WSMCMND_API_IMPORT template class WSMCMND_API std::_Compressed_pair,std::_Vector_val>,true>; 45 | WSMCMND_API_IMPORT template class WSMCMND_API std::vector>; 46 | // for vector< pair< int, string > > 47 | WSMCMND_API_IMPORT template class WSMCMND_API std::_Vector_val>>; 48 | WSMCMND_API_IMPORT template class WSMCMND_API std::_Compressed_pair>,std::_Vector_val>>,true>; 49 | WSMCMND_API_IMPORT template class WSMCMND_API std::vector,std::allocator>>; 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/include/enums.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of either the GNU General Public License (GPL) 8 | or the GNU Lesser General Public License (LGPL), as published by the Free Software 9 | Foundation, either version 3 of the Licenses, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Copies of the GNU GPL and LGPL are included with this project 17 | and are available at . 18 | */ 19 | 20 | #pragma once 21 | 22 | #ifdef WSMCMND_ENUM_EXPORT 23 | #undef WSMCMND_ENUM_EXPORT 24 | #undef WSMCMND_ENUM_NAMESPACE 25 | #endif 26 | 27 | #define WSMCMND_ENUM_EXPORT 28 | #define WSMCMND_ENUM_NAMESPACE WASimCommander::Enums 29 | 30 | #include "./enums_impl.h" 31 | -------------------------------------------------------------------------------- /src/include/global.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of either the GNU General Public License (GPL) 8 | or the GNU Lesser General Public License (LGPL), as published by the Free Software 9 | Foundation, either version 3 of the Licenses, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Copies of the GNU GPL and LGPL are included with this project 17 | and are available at . 18 | */ 19 | 20 | #pragma once 21 | 22 | // the macros _staticLibrary/_library/_exe are set in the common.props file at the src root 23 | #ifndef WSMCMND_API 24 | # if defined(WSMCMND_API_STATIC) || defined(_staticlibrary) || defined(_MSFS_WASM) 25 | # define WSMCMND_API 26 | # else 27 | # if defined(WSMCMND_API_EXPORT) || defined(_library) 28 | # define WSMCMND_API __declspec(dllexport) 29 | # define WSMCMND_API_IMPORT 30 | # else /* defined(_exe) */ 31 | # define WSMCMND_API __declspec(dllimport) 32 | # define WSMCMND_API_IMPORT extern 33 | # endif 34 | # endif 35 | #endif 36 | 37 | // grrr.... 38 | #ifdef min 39 | #undef min 40 | #undef max 41 | #endif 42 | -------------------------------------------------------------------------------- /src/include/wasim_version.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of either the GNU General Public License (GPL) 8 | or the GNU Lesser General Public License (LGPL), as published by the Free Software 9 | Foundation, either version 3 of the Licenses, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Copies of the GNU GPL and LGPL are included with this project 17 | and are available at . 18 | */ 19 | 20 | // THIS FILE IS GENERATED BY A SCRIPT, CHANGES WILL NOT PERSIST. EDIT THE CORRESPONDING .in TEMPLATE FILE INSTEAD. 21 | 22 | #pragma once 23 | 24 | #define WSMCMND_PROJECT_NAME "WASimCommander" 25 | #define WSMCMND_CLIENT_NAME "WASimClient" 26 | #define WSMCMND_SERVER_NAME "WASimModule" 27 | #define WSMCMND_GUI_NAME "WASimUI" 28 | 29 | #define WSMCMND_VER_MAJOR 1 30 | #define WSMCMND_VER_MINOR 3 31 | #define WSMCMND_VER_PATCH 2 32 | #define WSMCMND_VER_BUILD 0 33 | // Git commit hash (top 8 bytes) 34 | #define WSMCMND_VER_COMIT 0x422864C2UL 35 | /// Version number in 32 bit "binary coded decimal", eg. 0x01230400 = 1.23.4.0 36 | #define WSMCMND_VERSION 0x01030200UL 37 | /// Possible version suffix, eg "-beta1" (can be blank for release versions) 38 | #define WSMCMND_VER_NAME "" 39 | /// Dotted version string Maj.Min.Pat.Bld, eg. "1.23.4.0" 40 | #define WSMCMND_VERSION_STR "1.3.2.0" 41 | /// Dotted version string with possible suffix, eg. "1.23.4.0-beta1" 42 | #define WSMCMND_VERSION_INFO "1.3.2.0" 43 | /// Build date & time in ISO-8601 "Zulu Time" format, UTC 44 | #define WSMCMND_BUILD_DATE "2025-05-18T07:25:35Z" 45 | 46 | 47 | #define WSMCMND_PROJECT_URL "https://github.com/mpaperno/WASimCommander" 48 | #define WSMCMND_PROJECT_COPYRIGHT "Copyright Maxim Paperno; All rights reserved." 49 | #define WSMCMND_PROJECT_DESCRIPT "Remote access to the Microsoft Flight Simulator 2020 & 2024 Gauge API." 50 | #define WSMCMND_PROJECT_LICENSE "WASimCommander API and WASimClient licensed under LGPL v3 or GPL v3. WASimModule and all other code licensed under GPL v3. Full terms are detailed in the README, LICENSE.GPL.txt, and LICENSE.LGPL.txt files which should accompany this distribution and are available at the project's URL." 51 | -------------------------------------------------------------------------------- /src/include/wasim_version.in: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of either the GNU General Public License (GPL) 8 | or the GNU Lesser General Public License (LGPL), as published by the Free Software 9 | Foundation, either version 3 of the Licenses, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Copies of the GNU GPL and LGPL are included with this project 17 | and are available at . 18 | */ 19 | 20 | // @AUTOGEN_MSG@ 21 | 22 | #pragma once 23 | 24 | #define WSMCMND_PROJECT_NAME "@PROJECT_NAME@" 25 | #define WSMCMND_CLIENT_NAME "@CLIENT_NAME@" 26 | #define WSMCMND_SERVER_NAME "@SERVER_NAME@" 27 | #define WSMCMND_GUI_NAME "@APP_GUI_NAME@" 28 | 29 | #define WSMCMND_VER_MAJOR @VER_MAJOR@ 30 | #define WSMCMND_VER_MINOR @VER_MINOR@ 31 | #define WSMCMND_VER_PATCH @VER_PATCH@ 32 | #define WSMCMND_VER_BUILD @VER_BUILD@ 33 | // Git commit hash (top 8 bytes) 34 | #define WSMCMND_VER_COMIT @VER_COMIT@UL 35 | /// Version number in 32 bit "binary coded decimal", eg. 0x01230400 = 1.23.4.0 36 | #define WSMCMND_VERSION @VERSION@UL 37 | /// Possible version suffix, eg "-beta1" (can be blank for release versions) 38 | #define WSMCMND_VER_NAME "@VER_NAME@" 39 | /// Dotted version string Maj.Min.Pat.Bld, eg. "1.23.4.0" 40 | #define WSMCMND_VERSION_STR "@VERSION_STRING@" 41 | /// Dotted version string with possible suffix, eg. "1.23.4.0-beta1" 42 | #define WSMCMND_VERSION_INFO "@VERSION_STRING@@VER_NAME@" 43 | /// Build date & time in ISO-8601 "Zulu Time" format, UTC 44 | #define WSMCMND_BUILD_DATE "@BUILD_DATE@" 45 | 46 | 47 | #define WSMCMND_PROJECT_URL "@PROJECT_URL@" 48 | #define WSMCMND_PROJECT_COPYRIGHT "@PROJECT_COPY@" 49 | #define WSMCMND_PROJECT_DESCRIPT "@PROJECT_DESC@" 50 | #define WSMCMND_PROJECT_LICENSE "@PROJECT_LIC@" 51 | -------------------------------------------------------------------------------- /src/shared/SimConnectHelper.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of either the GNU General Public License (GPL) 8 | or the GNU Lesser General Public License (LGPL), as published by the Free Software 9 | Foundation, either version 3 of the Licenses, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Copies of the GNU GPL and LGPL are included with this project 17 | and are available at . 18 | */ 19 | 20 | // ---------- NOTE ---------------- 21 | // THE CONTENTS OF THIS FILE ARE NOT PART OF THE PUBLIC API. 22 | // The functions here are shared between implementations of the WASimCommander Server 23 | // and Client and are considered "implementation details" which may change at any time. 24 | // --------------------------------- 25 | 26 | #pragma once 27 | 28 | #include 29 | #ifndef _LIBCPP_HAS_NO_THREADS 30 | # include 31 | #endif 32 | 33 | #include "WASimCommander.h" 34 | #include "utilities.h" 35 | #include "SimConnectRequestTracker.h" 36 | 37 | namespace WASimCommander { 38 | namespace Utilities { 39 | namespace SimConnectHelper { 40 | 41 | static bool ENABLE_SIMCONNECT_REQUEST_TRACKING = false; // this can be changed even at runtime 42 | #ifndef _LIBCPP_HAS_NO_THREADS 43 | static std::mutex g_simConnectMutex; 44 | #endif 45 | 46 | // The macro allows us to only pass the function name once to get both the string version and the actual callable. 47 | // "SimConnect_" is automatically prepended to the callable version. 48 | // (For all the fancy new C++ features, no std way to get function name even at compile time... we still need macros :-| ) 49 | #define INVOKE_SIMCONNECT(F, ...) WASimCommander::Utilities::SimConnectHelper::invokeSimConnect(#F, &SimConnect_##F, __VA_ARGS__) 50 | 51 | static SimConnectRequestTracker *simRequestTracker() 52 | { 53 | static SimConnectRequestTracker tracker { /*maxRecords*/ 200 }; 54 | return &tracker; 55 | } 56 | 57 | // Main SimConnect function invoker template which does the actual call, logs any error or creates a request record, and returns the HRESULT from SimConnect. 58 | template 59 | static HRESULT simConnectProxy(const char *fname, std::function f, HANDLE hSim, Args... args) 60 | { 61 | #ifndef _LIBCPP_HAS_NO_THREADS 62 | std::lock_guard lock(g_simConnectMutex); 63 | #endif 64 | const HRESULT hr = std::bind(f, std::forward(hSim), std::forward(args)...)(); 65 | if FAILED(hr) 66 | LOG_ERR << "Error: " << fname << '(' << SimConnectRequestTracker::printArgs(args...) << ") failed with " << LOG_HR(hr); 67 | else if (ENABLE_SIMCONNECT_REQUEST_TRACKING) 68 | SimConnectHelper::simRequestTracker()->addRequestRecord(hSim, fname, args...); 69 | return hr; 70 | } 71 | 72 | // Because we really want type deduction, we can invoke simConnectProxy() via this template w/out specifying each argument type. 73 | template 74 | static HRESULT invokeSimConnect(const char *fname, HRESULT(*f)(HANDLE, Args...), HANDLE hSim, Args... args) { 75 | return simConnectProxy(fname, std::function(f), hSim, args...); 76 | } 77 | 78 | static void setMaxTrackedRequests(uint32_t maxRecords) { 79 | simRequestTracker()->setMaxRecords(maxRecords); 80 | } 81 | 82 | static void logSimConnectException(void *pData) 83 | { 84 | SIMCONNECT_RECV_EXCEPTION *data = reinterpret_cast(pData); 85 | if (ENABLE_SIMCONNECT_REQUEST_TRACKING) 86 | LOG_WRN << "SimConnect exception: " << simRequestTracker()->getRequestRecord(data->dwSendID, data->dwException, data->dwIndex); 87 | else 88 | LOG_WRN << "SimConnect exception: " << SimConnectRequestTracker::exceptionName(data->dwException) << "; SendId: " << data->dwSendID << "; Index: " << data->dwIndex; 89 | } 90 | 91 | static void logSimVersion(void* pData) 92 | { 93 | SIMCONNECT_RECV_OPEN *d = reinterpret_cast(pData); 94 | LOG_INF << "Connected to Simulator " << std::quoted(d->szApplicationName) 95 | << " v" << d->dwApplicationVersionMajor << '.' << d->dwApplicationVersionMinor << '.' << d->dwApplicationBuildMajor << '.' << d->dwApplicationBuildMinor 96 | << ", with SimConnect v" << d->dwSimConnectVersionMajor << '.' << d->dwSimConnectVersionMinor << '.' << d->dwSimConnectBuildMajor << '.' << d->dwSimConnectBuildMinor 97 | << " (Server v" << d->dwVersion << ')'; 98 | } 99 | 100 | static HRESULT addClientDataDefinition(HANDLE hSim, DWORD cddId, DWORD szOrType, float epsilon = 0.0f, DWORD offset = -1 /*SIMCONNECT_CLIENTDATAOFFSET_AUTO*/) 101 | { 102 | return INVOKE_SIMCONNECT(AddToClientDataDefinition, hSim, (SIMCONNECT_CLIENT_DATA_DEFINITION_ID)cddId, offset, szOrType, epsilon, SIMCONNECT_UNUSED); 103 | } 104 | 105 | static HRESULT removeClientDataDefinition(HANDLE hSim, DWORD cddId) 106 | { 107 | return INVOKE_SIMCONNECT(ClearClientDataDefinition, hSim, (SIMCONNECT_CLIENT_DATA_DEFINITION_ID)cddId); 108 | } 109 | 110 | static HRESULT registerDataArea(HANDLE hSim, const std::string &name, DWORD cdaID, DWORD cddId, DWORD szOrType, bool createCDA, bool readonly = false, float epsilon = 0.0f) 111 | { 112 | HRESULT hr; 113 | // Map a unique named data storage area to CDA ID. 114 | if FAILED(hr = INVOKE_SIMCONNECT(MapClientDataNameToID, hSim, name.c_str(), (SIMCONNECT_CLIENT_DATA_ID)cdaID)) 115 | return hr; 116 | if (createCDA) { 117 | // Reserve data storage area for actual size using the CDA ID. 118 | const uint32_t actualSize = getActualValueSize(szOrType); 119 | if FAILED(hr = INVOKE_SIMCONNECT(CreateClientData, hSim, cdaID, (DWORD)actualSize, readonly ? SIMCONNECT_CREATE_CLIENT_DATA_FLAG_READ_ONLY : SIMCONNECT_CREATE_CLIENT_DATA_FLAG_DEFAULT)) 120 | return hr; 121 | } 122 | // Define a single storage space within the data store using the CDA DefineID, of the full given size and automatic offset. 123 | if (cddId) 124 | return addClientDataDefinition(hSim, cddId, szOrType, epsilon); 125 | return S_OK; 126 | } 127 | 128 | static HRESULT newClientEvent(HANDLE hSim, DWORD evId, const std::string &evName, DWORD grpId = -1, DWORD priority = 0, bool maskable = false) 129 | { 130 | HRESULT hr; 131 | if FAILED(hr = INVOKE_SIMCONNECT(MapClientEventToSimEvent, hSim, (SIMCONNECT_CLIENT_EVENT_ID)evId, evName.c_str())) 132 | return hr; 133 | if ((int)grpId == -1) 134 | return hr; 135 | if FAILED(hr = INVOKE_SIMCONNECT(AddClientEventToNotificationGroup, hSim, (SIMCONNECT_NOTIFICATION_GROUP_ID)grpId, (SIMCONNECT_CLIENT_EVENT_ID)evId, (BOOL)maskable)) 136 | return hr; 137 | if (priority) 138 | hr = INVOKE_SIMCONNECT(SetNotificationGroupPriority, hSim, (SIMCONNECT_NOTIFICATION_GROUP_ID)grpId, priority); 139 | return hr; 140 | } 141 | 142 | } // SimConnectHelper 143 | } // Utilities 144 | } // WASimCommander 145 | -------------------------------------------------------------------------------- /src/shared/utilities.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the WASimCommander project. 3 | https://github.com/mpaperno/WASimCommander 4 | 5 | COPYRIGHT: (c) Maxim Paperno; All Rights Reserved. 6 | 7 | This file may be used under the terms of either the GNU General Public License (GPL) 8 | or the GNU Lesser General Public License (LGPL), as published by the Free Software 9 | Foundation, either version 3 of the Licenses, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Copies of the GNU GPL and LGPL are included with this project 17 | and are available at . 18 | */ 19 | 20 | // ---------- NOTE ---------------- 21 | // THE CONTENTS OF THIS FILE ARE NOT PART OF THE PUBLIC API. 22 | // The functions here are shared between implementations of the WASimCommander Server 23 | // and Client and are considered "implementation details" which may change at any time. 24 | // --------------------------------- 25 | 26 | #pragma once 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | //#include 36 | 37 | #include "WASimCommander.h" 38 | //#include "SimConnectRequestTracker.h" 39 | 40 | #define LOGFAULT_USE_UTCZONE 0 41 | #define LOGFAULT_TIME_PRINT_TIMEZONE 0 42 | #define LOGFAULT_USE_SHORT_LOG_MACROS 1 43 | #define LOGFAULT_TIME_PRINT_MILLISECONDS 1 44 | #define LOGFAULT_TIME_FORMAT "%m-%d %H:%M:%S." 45 | #define LOGFAULT_LEVEL_NAMES {"[NON]", "[CRT]", "[ERR]", "[WRN]", "[INF]", "[DBG]", "[TRC]"} 46 | #if defined(_LIBCPP_HAS_NO_THREADS) || defined(__cplusplus_cli) 47 | # define LOGFAULT_USE_THREADING 0 48 | #else 49 | # define LOGFAULT_USE_THREADING 1 50 | #endif 51 | #ifndef LOGFAULT_THREAD_NAME 52 | # define LOGFAULT_THREAD_NAME WSMCMND_PROJECT_NAME 53 | #endif 54 | #include "logfault.h" 55 | 56 | #define WSMCMND_SHORT_NAME "WASim" 57 | 58 | #define STREAM_HEX LOG_HEX 59 | #define STREAM_HEX2 LOG_HEX2 60 | #define STREAM_HEX4 LOG_HEX4 61 | #define STREAM_HEX8 LOG_HEX8 62 | #define LOG_HR(hr) "HRESULT 0x" << STREAM_HEX8(hr) 63 | 64 | #define LOG_SC_RECV(D) "[SIMCONNECT_RECV] ID: " << D->dwID << "; Size: " << D->dwSize 65 | #define LOG_SC_RECV_EVENT(D) "[SIMCONNECT_RECV_EVENT] GroupID: " << D->uGroupID << "; EventID: " << D->uEventID << "; Data: " << D->dwData 66 | #define LOG_SC_RCV_CLIENT_DATA(D) "[SIMCONNECT_RECV_CLIENT_DATA] ObjID: " << D->dwObjectID << "; DefID: " << D->dwDefineID << "; ReqID: " << D->dwRequestID << "; DefineCount: " << D->dwDefineCount 67 | 68 | namespace WASimCommander { 69 | namespace Utilities 70 | { 71 | 72 | // Event name constants for building event and data area names. 73 | static const char EVENT_NAME_CONNECT[] = WSMCMND_COMMON_NAME_PREFIX WSMCMND_EVENT_NAME_CONNECT; 74 | static const char EVENT_NAME_PING[] = WSMCMND_COMMON_NAME_PREFIX WSMCMND_EVENT_NAME_PING; 75 | static const char EVENT_NAME_PING_PFX[] = WSMCMND_COMMON_NAME_PREFIX WSMCMND_EVENT_NAME_PING "."; // + 8 char client name 76 | static const char CDA_NAME_CMD_PFX[] = WSMCMND_COMMON_NAME_PREFIX WSMCMND_CDA_NAME_COMMAND "."; // + 8 char client name 77 | static const char CDA_NAME_RESP_PFX[] = WSMCMND_COMMON_NAME_PREFIX WSMCMND_CDA_NAME_RESPONSE "."; // + 8 char client name 78 | static const char CDA_NAME_LOG_PFX[] = WSMCMND_COMMON_NAME_PREFIX WSMCMND_CDA_NAME_LOG "."; // + 8 char client name 79 | static const char CDA_NAME_DATA_PFX[] = WSMCMND_COMMON_NAME_PREFIX WSMCMND_CDA_NAME_DATA "."; // + 8 char client name [+ "." + request ID (0-65535)] 80 | static const char CDA_NAME_KEYEV_PFX[] = WSMCMND_COMMON_NAME_PREFIX WSMCMND_CDA_NAME_KEYEVENT "."; // + 8 char client name 81 | 82 | static bool isIndexedVariableType(const char type) { 83 | static const std::vector VAR_TYPES_INDEXED = { 'A', 'L', 'T' }; 84 | return find(VAR_TYPES_INDEXED.cbegin(), VAR_TYPES_INDEXED.cend(), type) != VAR_TYPES_INDEXED.cend(); 85 | } 86 | 87 | static bool isUnitBasedVariableType(const char type) { 88 | static const std::vector VAR_TYPES_UNIT_BASED = { 'A', 'C', 'E', 'L', 'P' }; 89 | return find(VAR_TYPES_UNIT_BASED.cbegin(), VAR_TYPES_UNIT_BASED.cend(), type) != VAR_TYPES_UNIT_BASED.cend(); 90 | } 91 | 92 | static bool isSettableVariableType(const char type) { 93 | static const std::vector VAR_TYPES_SETTABLE = { 'A', 'B', 'C', 'H', 'K', 'L', 'Z' }; 94 | return find(VAR_TYPES_SETTABLE.cbegin(), VAR_TYPES_SETTABLE.cend(), type) != VAR_TYPES_SETTABLE.cend(); 95 | } 96 | 97 | // returns actual byte size from given size which may be one of the SimConnect_AddToClientDataDefinition() dwSizeOrType constants 98 | static constexpr uint32_t getActualValueSize(DWORD dwSizeOrType) 99 | { 100 | if (dwSizeOrType < DATA_TYPE_DOUBLE) 101 | return dwSizeOrType; 102 | switch (dwSizeOrType) { 103 | case DATA_TYPE_INT8: 104 | return 1; 105 | case DATA_TYPE_INT16: 106 | return 2; 107 | case DATA_TYPE_INT32: 108 | case DATA_TYPE_FLOAT: 109 | return 4; 110 | case DATA_TYPE_INT64: 111 | case DATA_TYPE_DOUBLE: 112 | return 8; 113 | default: 114 | return dwSizeOrType; 115 | } 116 | } 117 | 118 | static inline bool fuzzyCompare(float p1, float p2) { 119 | p1 += 1.0f; p2 += 1.0f; 120 | return (std::fabs(p1 - p2) * 1000000.f <= std::min(std::fabs(p1), std::fabs(p2))); 121 | } 122 | 123 | // Custom "+" operator for strong enum types to cast to underlying type. 124 | template ::value, bool> = true> 125 | constexpr auto operator+(T e) noexcept { 126 | return static_cast>(e); 127 | } 128 | 129 | template 130 | static int indexOfString(const Range &range, const char *c) noexcept 131 | { 132 | int i = 0; 133 | auto b = std::cbegin(range), e = std::cend(range); 134 | while (b != e && strcmp(*b, c)) 135 | ++b, ++i; 136 | return b == e ? -1 : i; 137 | } 138 | 139 | template ::value, bool> = true> 140 | static const auto getEnumName(Enum e, const Range &range) noexcept 141 | { 142 | using T = typename std::iterator_traits::value_type; 143 | const size_t len = std::cend(range) - std::cbegin(range); 144 | if ((size_t)e < len) 145 | return range[(size_t)e]; 146 | return T(); 147 | } 148 | 149 | template 150 | static const std::string byteArrayToHex(const T *range, size_t len, const char sep = ':') noexcept 151 | { 152 | std::ostringstream os; 153 | for (size_t i=0; i < len; ++i) { 154 | if (i) 155 | os << sep; 156 | os << STREAM_HEX2(((unsigned short)*(range + i) & 0xFF)); 157 | } 158 | return os.str(); 159 | } 160 | 161 | template 162 | static std::string timePointToString(const Tp &tp, const std::string &format = std::string(LOGFAULT_TIME_FORMAT), bool withMs = true, bool utc = true) 163 | { 164 | const typename Tp::duration tt = tp.time_since_epoch(); 165 | const time_t durS = std::chrono::duration_cast(tt).count(); 166 | std::ostringstream ss; 167 | if (const std::tm *tm = (utc ? std::gmtime(&durS) : std::localtime(&durS))) { 168 | ss << std::put_time(tm, format.c_str()); 169 | if (withMs) { 170 | const long long durMs = std::chrono::duration_cast(tt).count(); 171 | ss << std::setw(3) << std::setfill('0') << int(durMs - durS * 1000); 172 | } 173 | } 174 | // gmtime/localtime() returned null 175 | else { 176 | ss << ""; 177 | } 178 | return ss.str(); 179 | } 180 | 181 | } // Utilities 182 | } // WASimCommander 183 | --------------------------------------------------------------------------------