├── pluginversion.txt ├── VatsimNAAATS ├── SetupWindow.cpp ├── VatsimNAAATS.rc ├── VatsimNAAATS.aps ├── res │ └── VatsimNAAATS.rc2 ├── VatsimNAAATS.def ├── pch.cpp ├── ApiSettings.example.h ├── VatsimNAAATS.vcxproj.user ├── targetver.h ├── Resource.h ├── VatsimNAAATS.h ├── RCLList.h ├── ConflictList.h ├── NAAATS.h ├── Styles.cpp ├── OtherList.h ├── InboundList.h ├── SetupWindow.h ├── pch.h ├── Overlays.h ├── BaseList.h ├── BaseList.cpp ├── Logger.h ├── NAAATS.cpp ├── RoutesHelper.h ├── NotePad.h ├── RCLList.cpp ├── framework.h ├── MessageWindow.h ├── CommonRenders.h ├── TrackInfoWindow.h ├── VatsimNAAATS.sln ├── VatsimNAAATS.cpp ├── BaseWindow.h ├── AcTargets.h ├── DataHandler.h ├── BaseWindow.cpp ├── MenuBar.h ├── OtherList.cpp ├── ConflictDetection.h ├── ConflictList.cpp ├── RadarDisplay.h ├── Logger.cpp ├── NotePad.cpp ├── InboundList.cpp ├── Styles.h ├── Overlays.cpp ├── Utils.h ├── VatsimNAAATS.vcxproj.filters ├── Constants.h ├── FlightPlanWindow.h ├── TrackInfoWindow.cpp ├── Structures.h ├── MessageWindow.cpp ├── VatsimNAAATS.vcxproj ├── RoutesHelper.cpp ├── MenuBar.cpp └── CommonRenders.cpp ├── .gitignore ├── README.md └── LICENSE /pluginversion.txt: -------------------------------------------------------------------------------- 1 | 1.3b2 -------------------------------------------------------------------------------- /VatsimNAAATS/SetupWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "SetupWindow.h" 3 | -------------------------------------------------------------------------------- /VatsimNAAATS/VatsimNAAATS.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vNAAATS/vatsim-NAAATS/HEAD/VatsimNAAATS/VatsimNAAATS.rc -------------------------------------------------------------------------------- /VatsimNAAATS/VatsimNAAATS.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vNAAATS/vatsim-NAAATS/HEAD/VatsimNAAATS/VatsimNAAATS.aps -------------------------------------------------------------------------------- /VatsimNAAATS/res/VatsimNAAATS.rc2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vNAAATS/vatsim-NAAATS/HEAD/VatsimNAAATS/res/VatsimNAAATS.rc2 -------------------------------------------------------------------------------- /VatsimNAAATS/VatsimNAAATS.def: -------------------------------------------------------------------------------- 1 | ; VatsimNAAATS.def : Declares the module parameters for the DLL. 2 | 3 | LIBRARY 4 | 5 | EXPORTS 6 | ; Explicit exports can go here 7 | -------------------------------------------------------------------------------- /VatsimNAAATS/pch.cpp: -------------------------------------------------------------------------------- 1 | // pch.cpp: source file corresponding to the pre-compiled header 2 | 3 | #include "pch.h" 4 | 5 | // When you are using pre-compiled headers, this source file is necessary for compilation to succeed. 6 | -------------------------------------------------------------------------------- /VatsimNAAATS/ApiSettings.example.h: -------------------------------------------------------------------------------- 1 | #ifndef API_SETTINGS_H 2 | #define API_SETTINGS_H 3 | 4 | #include 5 | #pragma once 6 | //api info 7 | namespace ApiSettings 8 | { 9 | const std::string apiUrl = "", 10 | apiKey = ""; 11 | } 12 | 13 | #endif -------------------------------------------------------------------------------- /VatsimNAAATS/VatsimNAAATS.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | -------------------------------------------------------------------------------- /VatsimNAAATS/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /VatsimNAAATS/Resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by VatsimNAAATS.rc 4 | // 5 | 6 | // Next default values for new objects 7 | // 8 | #ifdef APSTUDIO_INVOKED 9 | #ifndef APSTUDIO_READONLY_SYMBOLS 10 | 11 | #define _APS_NEXT_RESOURCE_VALUE 1000 12 | #define _APS_NEXT_CONTROL_VALUE 1000 13 | #define _APS_NEXT_SYMED_VALUE 1000 14 | #define _APS_NEXT_COMMAND_VALUE 32771 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /VatsimNAAATS/VatsimNAAATS.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef __AFXWIN_H__ 3 | #error "include 'pch.h' before including this file for PCH" 4 | #endif 5 | #include "resource.h" 6 | #include 7 | #include "Logger.h" 8 | 9 | // Main App 10 | class CVatsimNAAATSApp : public CWinApp 11 | { 12 | public: 13 | CVatsimNAAATSApp(); 14 | 15 | // Overrides 16 | public: 17 | virtual BOOL InitInstance(); 18 | 19 | DECLARE_MESSAGE_MAP() 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /VatsimNAAATS/RCLList.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "Structures.h" 9 | #include "BaseList.h" 10 | 11 | using namespace std; 12 | using namespace Gdiplus; 13 | using namespace EuroScopePlugIn; 14 | 15 | class CRCLList : public CBaseList 16 | { 17 | public: 18 | CRCLList(POINT topLeft); 19 | virtual void RenderList(Graphics* g, CDC* dc, CRadarScreen* screen); 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /VatsimNAAATS/ConflictList.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "Structures.h" 9 | #include "BaseList.h" 10 | #include "ConflictDetection.h" 11 | 12 | using namespace std; 13 | using namespace Gdiplus; 14 | using namespace EuroScopePlugIn; 15 | 16 | class CConflictList : public CBaseList 17 | { 18 | public: 19 | CConflictList(POINT topLeft); 20 | virtual void RenderList(Graphics* g, CDC* dc, CRadarScreen* screen); 21 | }; 22 | -------------------------------------------------------------------------------- /VatsimNAAATS/NAAATS.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | using namespace EuroScopePlugIn; 6 | 7 | // Main plugin header 8 | class CNAAATSPlugin : public CPlugIn 9 | { 10 | public: 11 | // Constructor & destructor 12 | CNAAATSPlugin(); 13 | virtual ~CNAAATSPlugin(); 14 | 15 | // OnRadarScreenCreated event 16 | CRadarScreen* OnRadarScreenCreated(const char* sDisplayName, bool NeedRadarContent, bool GeoReferenced, bool CanBeSaved, bool CanBeCreated); 17 | private: 18 | // Register the radar display 19 | void Register(); 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /VatsimNAAATS/Styles.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "Styles.h" 4 | 5 | // Initialise font values here because otherwise we get lots of linker errors 6 | CFont FontSelector::normalFont14; 7 | CFont FontSelector::normalFont15; 8 | CFont FontSelector::normalFont16; 9 | CFont FontSelector::normalFont30; 10 | CFont FontSelector::monoFont12; 11 | CFont FontSelector::monoFont14; 12 | CFont FontSelector::monoFont15; 13 | CFont FontSelector::atcFont14; 14 | CFont FontSelector::atcFont15; 15 | CFont FontSelector::atcFont16; 16 | CFont FontSelector::atcFont18; 17 | bool FontSelector::fontsInitialised; -------------------------------------------------------------------------------- /VatsimNAAATS/OtherList.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "BaseList.h" 9 | 10 | using namespace std; 11 | using namespace Gdiplus; 12 | using namespace EuroScopePlugIn; 13 | 14 | class COtherList : public CBaseList 15 | { 16 | public: 17 | COtherList(POINT topLeft); 18 | virtual void RenderList(Graphics* g, CDC* dc, CRadarScreen* screen); 19 | 20 | // Aircraft list 21 | static vector AircraftList; 22 | 23 | // Hides and shows 24 | bool HideShowButton = true; 25 | }; 26 | -------------------------------------------------------------------------------- /VatsimNAAATS/InboundList.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "Structures.h" 9 | #include "BaseList.h" 10 | 11 | using namespace std; 12 | using namespace Gdiplus; 13 | using namespace EuroScopePlugIn; 14 | 15 | class CInboundList : public CBaseList 16 | { 17 | public: 18 | CInboundList(POINT topLeft); 19 | virtual void RenderList(Graphics* g, CDC* dc, CRadarScreen* screen); 20 | 21 | // Aircraft list 22 | static vector AircraftList; 23 | 24 | // Hides and shows 25 | bool HideShowButton = true; 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /VatsimNAAATS/SetupWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "BaseWindow.h" 3 | class CSetupWindow : public CBaseWindow 4 | { 5 | public: 6 | // Inherited methods 7 | CSetupWindow(POINT topLeft); 8 | virtual void RenderWindow(CDC* dc, Graphics* g, CRadarScreen* screen); 9 | virtual void MakeWindowItems(); 10 | virtual void ButtonDown(int id) = 0; 11 | virtual void ButtonUp(int id, CRadarScreen* screen = nullptr); 12 | virtual void ButtonPress(int id); 13 | virtual void ButtonUnpress(int id) = 0; 14 | virtual void SetButtonState(int id, CInputState state); 15 | 16 | // Child methods 17 | void SetTextValue(CRadarScreen* screen, int id, string content); 18 | }; 19 | 20 | -------------------------------------------------------------------------------- /VatsimNAAATS/pch.h: -------------------------------------------------------------------------------- 1 | // pch.h: This is a precompiled header file. 2 | // Files listed below are compiled only once, improving build performance for future builds. 3 | // This also affects IntelliSense performance, including code completion and many code browsing features. 4 | // However, files listed here are ALL re-compiled if any one of them is updated between builds. 5 | // Do not add files here that you will be updating frequently as this negates the performance advantage. 6 | 7 | #ifndef PCH_H 8 | #define PCH_H 9 | 10 | // add headers that you want to pre-compile here 11 | #include "framework.h" 12 | 13 | #include 14 | #pragma comment(lib, "Gdiplus.lib") 15 | 16 | #endif //PCH_H 17 | -------------------------------------------------------------------------------- /VatsimNAAATS/Overlays.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "Constants.h" 6 | #include "Structures.h" 7 | #include "CommonRenders.h" 8 | #include "MenuBar.h" 9 | 10 | using namespace std; 11 | using namespace Gdiplus; 12 | using namespace EuroScopePlugIn; 13 | 14 | class COverlays 15 | { 16 | public: 17 | // Current overlay type 18 | static COverlayType CurrentType; 19 | 20 | // Display the currently selected overlay 21 | static void ShowCurrentOverlay(CDC* dc, Graphics* g, CRadarScreen* screen, CMenuBar* menubar); 22 | 23 | // Grid reference 24 | static void ShowHideGridReference(CRadarScreen* screen, bool show); 25 | }; 26 | 27 | 28 | -------------------------------------------------------------------------------- /VatsimNAAATS/BaseList.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "Structures.h" 8 | #include 9 | 10 | using namespace std; 11 | using namespace Gdiplus; 12 | using namespace EuroScopePlugIn; 13 | 14 | class CBaseList 15 | { 16 | public: 17 | CBaseList(POINT topLeft); 18 | virtual ~CBaseList() {}; 19 | POINT GetTopLeft(); 20 | void MoveList(CRect area); // By area 21 | void MoveList(POINT topLeft); // By top left point 22 | virtual void RenderList(Graphics* g, CDC* dc, CRadarScreen* screen) = 0; 23 | 24 | protected: 25 | // Top left point of list 26 | POINT topleft; 27 | }; 28 | 29 | -------------------------------------------------------------------------------- /VatsimNAAATS/BaseList.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "BaseList.h" 3 | 4 | CBaseList::CBaseList(POINT topLeft) { 5 | // Set top left 6 | topleft = topLeft; 7 | } 8 | 9 | POINT CBaseList::GetTopLeft() { 10 | return topleft; 11 | } 12 | 13 | void CBaseList::MoveList(CRect area) { 14 | // Only set Y if it is greater than the top position of the menu bar (to stop clipping over the menu bar) 15 | topleft = { area.left, area.top > MENBAR_HEIGHT ? area.top : MENBAR_HEIGHT }; 16 | } 17 | 18 | void CBaseList::MoveList(POINT topLeft) { 19 | // Only set Y if it is greater than the top position of the menu bar (to stop clipping over the menu bar) 20 | topleft = { topLeft.x, topLeft.y > MENBAR_HEIGHT ? topLeft.y : MENBAR_HEIGHT }; 21 | } -------------------------------------------------------------------------------- /VatsimNAAATS/Logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "EuroScopePlugIn.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "Utils.h" 9 | 10 | using namespace std; 11 | using namespace EuroScopePlugIn; 12 | 13 | class CLogger 14 | { 15 | public: 16 | // Log a message 17 | static void Log(CLogType type, string text, string invokedBy = ""); 18 | 19 | // Log to chat 20 | static void DebugLog(CRadarScreen* screen, string text); 21 | 22 | static void LogAircraftDebugInfo(string text); 23 | 24 | // Generate the log file 25 | static void InstantiateLogFile(); 26 | 27 | private: 28 | // The file to log to 29 | static string logFilePath; 30 | 31 | // Get log prefix (ID + date and time) 32 | static string GeneratePrefix(CLogType type); 33 | 34 | // To append lines after initialisation instead of overwriting 35 | static bool initialised; 36 | static bool initialisedAc; 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /VatsimNAAATS/NAAATS.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "NAAATS.h" 4 | #include 5 | 6 | #include "Constants.h" 7 | #include "RadarDisplay.h" 8 | #include "Utils.h" 9 | 10 | CNAAATSPlugin::CNAAATSPlugin() : CPlugIn(COMPATIBILITY_CODE, PLUGIN_NAME.c_str(), PLUGIN_VERSION.c_str(), PLUGIN_AUTHOR.c_str(), PLUGIN_COPYRIGHT.c_str()) 11 | { 12 | // Register the display 13 | this->Register(); 14 | } 15 | 16 | CNAAATSPlugin::~CNAAATSPlugin() { 17 | 18 | } 19 | 20 | CRadarScreen* CNAAATSPlugin::OnRadarScreenCreated(const char* sDisplayName, bool NeedRadarContent, bool GeoReferenced, bool CanBeSaved, bool CanBeCreated) 21 | { 22 | // Create new display if the display name matches the constant 23 | if (!strcmp(sDisplayName, DISPLAY_NAME)) { 24 | return new CRadarDisplay(); 25 | } 26 | 27 | return nullptr; 28 | } 29 | 30 | void CNAAATSPlugin::Register() { 31 | // Register the display type and prevent normal EuroScope traffic from rendering 32 | RegisterDisplayType(DISPLAY_NAME, false, true, true, true); 33 | } -------------------------------------------------------------------------------- /VatsimNAAATS/RoutesHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "EuroScopePlugIn.h" 3 | #include "Constants.h" 4 | #include "Structures.h" 5 | #include "Utils.h" 6 | 7 | using namespace std; 8 | using namespace EuroScopePlugIn; 9 | 10 | class CRoutesHelper 11 | { 12 | public: 13 | // Current NAT tracks 14 | static map CurrentTracks; 15 | 16 | // Current TMI 17 | static string CurrentTMI; 18 | 19 | // Active aircraft routes to draw 20 | static vector ActiveRoutes; 21 | 22 | // Get a route 23 | static bool GetRoute(CRadarScreen* screen, vector* routeVector, string callsign, CAircraftFlightPlan* copy = nullptr); 24 | 25 | // Initialise route 26 | static void InitialiseRoute(void* args); 27 | 28 | // Parse a raw route 29 | static int ParseRoute(CRadarScreen* screen, string callsign, string rawInput, bool isTrack = false, CAircraftFlightPlan* copy = nullptr); 30 | 31 | // Is on a NAT track 32 | static string OnNatTrack(CRadarScreen* screen, string callsign); 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /VatsimNAAATS/NotePad.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "EuroScopePlugIn.h" 4 | #include 5 | #include 6 | #include 7 | #include "BaseWindow.h" 8 | #include "BaseList.h" 9 | #include "Constants.h" 10 | #include "Structures.h" 11 | #include "CommonRenders.h" 12 | 13 | class CNotePad : public CBaseWindow, public CBaseList 14 | { 15 | public: 16 | // Inherited methods 17 | CNotePad(POINT topLeft, POINT topLeftList); 18 | virtual void RenderWindow(CDC* dc, Graphics* g, CRadarScreen* screen); 19 | virtual void MakeWindowItems(); 20 | virtual void ButtonDown(int id); 21 | virtual void ButtonUp(int id, CRadarScreen* screen = nullptr); 22 | virtual void ButtonPress(int id); 23 | virtual void ButtonUnpress(int id); 24 | virtual void SetButtonState(int id, CInputState state); 25 | virtual void RenderList(Graphics* g, CDC* dc, CRadarScreen* screen); 26 | 27 | // Button definitions 28 | static const int BTN_CLOSE; 29 | static const int BTN_SAVE; 30 | 31 | private: 32 | string savedNotePadContent; 33 | string newNotePadContent; 34 | }; 35 | 36 | -------------------------------------------------------------------------------- /VatsimNAAATS/RCLList.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Constants.h" 3 | #include "Styles.h" 4 | #include "Utils.h" 5 | #include "RCLList.h" 6 | 7 | using namespace Colours; 8 | 9 | CRCLList::CRCLList(POINT topLeft) : CBaseList(topLeft) { 10 | 11 | } 12 | 13 | // TODO: implement expand/retract button 14 | void CRCLList::RenderList(Graphics* g, CDC* dc, CRadarScreen* screen) { 15 | // Save context for later 16 | int sDC = dc->SaveDC(); 17 | 18 | // Make rectangle 19 | Rect rectangle(topleft.x, topleft.y, LIST_RCLS_WIDTH, 500); 20 | 21 | /// Make "RCLs" text 22 | // Font 23 | FontSelector::SelectMonoFont(15, dc); 24 | dc->SetTextColor(TextWhite.ToCOLORREF()); 25 | dc->SetTextAlign(TA_LEFT); 26 | 27 | // Don't show size if none 28 | //if ( ) { 29 | dc->TextOutA(rectangle.X, rectangle.Y, "RCLs"); 30 | //} 31 | // { 32 | //dc->TextOutA(rectangle.X, rectangle.Y, string("Others (" + to_string(AircraftList.size()) + ")").c_str()); 33 | //} 34 | 35 | // Get object area and add object to screen 36 | CRect area(topleft.x, topleft.y, topleft.x + LIST_RCLS_WIDTH, topleft.y + 14); 37 | screen->AddScreenObject(LIST_RCLS, "", area, true, ""); 38 | } -------------------------------------------------------------------------------- /VatsimNAAATS/framework.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef VC_EXTRALEAN 4 | #define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers 5 | #endif 6 | 7 | #include "targetver.h" 8 | 9 | #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit 10 | 11 | #include // MFC core and standard components 12 | #include // MFC extensions 13 | 14 | #ifndef _AFX_NO_OLE_SUPPORT 15 | #include // MFC OLE classes 16 | #include // MFC OLE dialog classes 17 | #include // MFC Automation classes 18 | #endif // _AFX_NO_OLE_SUPPORT 19 | 20 | #ifndef _AFX_NO_DB_SUPPORT 21 | #include // MFC ODBC database classes 22 | #endif // _AFX_NO_DB_SUPPORT 23 | 24 | #ifndef _AFX_NO_DAO_SUPPORT 25 | #include // MFC DAO database classes 26 | #endif // _AFX_NO_DAO_SUPPORT 27 | 28 | #ifndef _AFX_NO_OLE_SUPPORT 29 | #include // MFC support for Internet Explorer 4 Common Controls 30 | #endif 31 | #ifndef _AFX_NO_AFXCMN_SUPPORT 32 | #include // MFC support for Windows Common Controls 33 | #endif // _AFX_NO_AFXCMN_SUPPORT 34 | 35 | 36 | -------------------------------------------------------------------------------- /VatsimNAAATS/MessageWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "EuroScopePlugIn.h" 4 | #include 5 | #include 6 | #include 7 | #include "BaseWindow.h" 8 | #include "FlightPlanWindow.h" 9 | 10 | using namespace std; 11 | using namespace Gdiplus; 12 | using namespace EuroScopePlugIn; 13 | 14 | class CMessageWindow : public CBaseWindow 15 | { 16 | public: 17 | // Inherited methods 18 | CMessageWindow(POINT topLeft); 19 | virtual void RenderWindow(CDC* dc, Graphics* g, CRadarScreen* screen); 20 | virtual void MakeWindowItems(); 21 | virtual void ButtonDown(int id); 22 | virtual void ButtonUp(int id, CRadarScreen* screen = nullptr); 23 | virtual void ButtonPress(int id); 24 | void ButtonDoubleClick(CRadarScreen* screen, int id, CFlightPlanWindow* fltPlnWin); 25 | virtual void ButtonUnpress(int id); 26 | virtual void SetButtonState(int id, CInputState state); 27 | 28 | // Button definitions 29 | static const int BTN_CLOSE; 30 | 31 | // Currently active messages 32 | static unordered_map ActiveMessages; 33 | static unordered_map OngoingMessages; 34 | int SelectedMessage = -1; 35 | int MessageCount = 0; 36 | 37 | static const int SCRL_MSGWNDW = 520; 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /VatsimNAAATS/CommonRenders.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "EuroScopePlugIn.h" 4 | #include "Structures.h" 5 | #include "RoutesHelper.h" 6 | #include "DataHandler.h" 7 | #include "MenuBar.h" 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | using namespace Gdiplus; 13 | using namespace EuroScopePlugIn; 14 | 15 | class CCommonRenders // Commonly rendered items, here for ease of access 16 | { 17 | public: 18 | static CRect RenderButton(CDC* dc, CRadarScreen* screen, POINT topLeft, int width, int height, CWinButton* obj, int vtcAlign = -1); 19 | static void RenderTextInput(CDC* dc, CRadarScreen* screen, POINT topLeft, int width, int height, CTextInput* obj); 20 | static CRect RenderCheckBox(CDC* dc, Graphics* g, CRadarScreen* screen, POINT topLeft, int height, CCheckBox* obj); 21 | static void RenderDropDown(CDC* dc, Graphics* g, CRadarScreen* screen, POINT topLeft, int width, int height, CDropDown* obj); 22 | static void RenderScrollBar(CDC* dc, Graphics* g, CRadarScreen* screen, POINT topLeft, CWinScrollBar* scrollView); 23 | 24 | // Screen actions 25 | static void RenderTracks(CDC* dc, Graphics* g, CRadarScreen* screen, COverlayType type, CMenuBar* menubar); 26 | static void RenderRoutes(CDC* dc, Graphics* g, CRadarScreen* screen); 27 | static void RenderQDM(CDC* dc, Graphics* g, CRadarScreen* screen, CPosition* position1, CPosition* position2, POINT cursorPosition, CPosition* cursorLatlon); 28 | }; 29 | 30 | -------------------------------------------------------------------------------- /VatsimNAAATS/TrackInfoWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "EuroScopePlugIn.h" 4 | #include 5 | #include 6 | #include 7 | #include "BaseWindow.h" 8 | #include "MenuBar.h" 9 | 10 | using namespace std; 11 | using namespace Gdiplus; 12 | using namespace EuroScopePlugIn; 13 | 14 | class CTrackInfoWindow : public CBaseWindow 15 | { 16 | public: 17 | // Inherited methods 18 | CTrackInfoWindow(POINT topLeft); 19 | virtual void RenderWindow(CDC* dc, Graphics* g, CRadarScreen* screen) {}; 20 | void RenderWindow(CDC* dc, Graphics* g, CRadarScreen* screen, CMenuBar* menuBar); 21 | virtual void MakeWindowItems(); 22 | virtual void ButtonDown(int id); 23 | virtual void ButtonUp(int id, CRadarScreen* screen = nullptr); 24 | virtual void ButtonPress(int id); 25 | virtual void ButtonUnpress(int id); 26 | virtual void SetButtonState(int id, CInputState state); 27 | 28 | // Window methods 29 | void Scroll(CRect area, POINT mousePtr); 30 | 31 | // Window functions to do 32 | bool NATDataRefresh; 33 | 34 | // Window messages to display 35 | string MsgDataRefresh = ""; 36 | 37 | // Panel definitions 38 | static const int PANEL_BTNS; 39 | 40 | // Button definitions 41 | static const int BTN_CLOSE; 42 | static const int BTN_REFRESH; 43 | 44 | private: 45 | double trackScrollAreaSize; 46 | double gripPosDelta = 0; 47 | double gripSize; 48 | CRect currentScrollPos = CRect(0, 0, 0, 0); 49 | int scrollWindowSize; 50 | }; 51 | 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Folders 35 | .vs/ 36 | VatsimNAAATS/Debug/ 37 | Release 38 | VatsimNAAATS/enc_temp_folder/ce668a47c6fbff60567139a9c568b66/RadarDisplay.cpp 39 | VatsimNAAATS/ApiSettings.h 40 | *.vcxproj 41 | VatsimNAAATS/VatsimNAAATS.vcxproj 42 | VatsimNAAATS/Keys.h 43 | vNAAATS/vNAAATS/Debug/vNAAATS.tlog/vNAAATS.write.1u.tlog 44 | vNAAATS/vNAAATS/Debug/vNAAATS.tlog/vNAAATS.lastbuildstate 45 | vNAAATS/vNAAATS/Debug/vNAAATS.tlog/rc.write.1.tlog 46 | vNAAATS/vNAAATS/Debug/vNAAATS.tlog/rc.read.1.tlog 47 | vNAAATS/vNAAATS/Debug/vNAAATS.tlog/rc.command.1.tlog 48 | vNAAATS/vNAAATS/Debug/vNAAATS.tlog/link.write.1.tlog 49 | vNAAATS/vNAAATS/Debug/vNAAATS.tlog/link.read.1.tlog 50 | vNAAATS/vNAAATS/Debug/vNAAATS.tlog/link.command.1.tlog 51 | vNAAATS/vNAAATS/Debug/vNAAATS.tlog/CL.write.1.tlog 52 | vNAAATS/vNAAATS/Debug/vNAAATS.tlog/CL.read.1.tlog 53 | vNAAATS/vNAAATS/Debug/vNAAATS.tlog/CL.command.1.tlog 54 | vNAAATS/vNAAATS/Debug/vNAAATS.res 55 | vNAAATS/vNAAATS/Debug/vNAAATS.log 56 | vNAAATS/vNAAATS/Debug/vc140.pdb 57 | vNAAATS/vNAAATS/Debug/vc140.idb 58 | vNAAATS/Debug/vNAAATS.pdb 59 | vNAAATS/Debug/vNAAATS.ilk 60 | vNAAATS/Debug/vNAAATS.exp 61 | -------------------------------------------------------------------------------- /VatsimNAAATS/VatsimNAAATS.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29613.14 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VatsimNAAATS", "VatsimNAAATS.vcxproj", "{8E1E2CE6-DF6C-41D3-8BBF-8803D826031D}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {8E1E2CE6-DF6C-41D3-8BBF-8803D826031D}.Debug|x64.ActiveCfg = Debug|x64 17 | {8E1E2CE6-DF6C-41D3-8BBF-8803D826031D}.Debug|x64.Build.0 = Debug|x64 18 | {8E1E2CE6-DF6C-41D3-8BBF-8803D826031D}.Debug|x86.ActiveCfg = Debug|Win32 19 | {8E1E2CE6-DF6C-41D3-8BBF-8803D826031D}.Debug|x86.Build.0 = Debug|Win32 20 | {8E1E2CE6-DF6C-41D3-8BBF-8803D826031D}.Release|x64.ActiveCfg = Release|x64 21 | {8E1E2CE6-DF6C-41D3-8BBF-8803D826031D}.Release|x64.Build.0 = Release|x64 22 | {8E1E2CE6-DF6C-41D3-8BBF-8803D826031D}.Release|x86.ActiveCfg = Release|Win32 23 | {8E1E2CE6-DF6C-41D3-8BBF-8803D826031D}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {E86BA687-A0E7-42D9-A9A9-23CF9570B141} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /VatsimNAAATS/VatsimNAAATS.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "framework.h" 3 | #include "VatsimNAAATS.h" 4 | #include "EuroScopePlugIn.h" 5 | #include "NAAATS.h" 6 | #include 7 | 8 | #ifdef _DEBUG 9 | #define new DEBUG_NEW 10 | #endif 11 | 12 | using namespace Gdiplus; 13 | 14 | // Token for gdiplus 15 | ULONG_PTR m_gdiplusToken = 0; 16 | 17 | BEGIN_MESSAGE_MAP(CVatsimNAAATSApp, CWinApp) 18 | END_MESSAGE_MAP() 19 | 20 | CVatsimNAAATSApp::CVatsimNAAATSApp() {} 21 | 22 | CVatsimNAAATSApp theApp; 23 | EuroScopePlugIn::CPlugIn* pNAAATS = nullptr; 24 | 25 | BOOL CVatsimNAAATSApp::InitInstance() 26 | { 27 | CWinApp::InitInstance(); 28 | 29 | return TRUE; 30 | } 31 | 32 | // Plugin Initialisation 33 | void __declspec (dllexport) 34 | EuroScopePlugInInit(EuroScopePlugIn::CPlugIn** ppPlugInInstance) 35 | { 36 | AFX_MANAGE_STATE(AfxGetStaticModuleState()) 37 | 38 | // Initialize GDI+ 39 | GdiplusStartupInput gdiplusStartupInput; 40 | GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, nullptr); 41 | * ppPlugInInstance = (CPlugIn*)new CNAAATSPlugin(); 42 | 43 | // Get DLL path 44 | GetModuleFileNameA(HINSTANCE(&__ImageBase), CUtils::DllPathFile, sizeof(CUtils::DllPathFile)); 45 | CUtils::DllPath = CUtils::DllPathFile; 46 | CUtils::DllPath.resize(CUtils::DllPath.size() - strlen("VatsimNAAATS.dll")); 47 | 48 | // Instantiate logger as the very first thing we do 49 | if (DEBUG_MODE) 50 | CLogger::InstantiateLogFile(); 51 | } 52 | 53 | // Plugin exit 54 | void __declspec (dllexport) 55 | EuroScopePlugInExit(void) 56 | { 57 | AFX_MANAGE_STATE(AfxGetStaticModuleState()) 58 | GdiplusShutdown(m_gdiplusToken); 59 | delete pNAAATS; 60 | } -------------------------------------------------------------------------------- /VatsimNAAATS/BaseWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "EuroScopePlugIn.h" 4 | #include 5 | #include 6 | #include 7 | #include "Constants.h" 8 | #include "Structures.h" 9 | #include "CommonRenders.h" 10 | 11 | using namespace std; 12 | using namespace Gdiplus; 13 | using namespace EuroScopePlugIn; 14 | 15 | class CBaseWindow 16 | { 17 | public: 18 | // Methods 19 | CBaseWindow(POINT topLeft); 20 | virtual ~CBaseWindow() {}; 21 | POINT GetTopLeft(); 22 | void MoveWindow(CRect topleft); 23 | void Scroll(int id, POINT newPtr, POINT oldPtr); 24 | string GetTextValue(int id); 25 | virtual void RenderWindow(CDC* dc, Graphics* g, CRadarScreen* screen) = 0; 26 | virtual void MakeWindowItems() = 0; 27 | virtual void ButtonDown(int id) = 0; 28 | virtual void ButtonUp(int id, CRadarScreen* screen = nullptr) = 0; 29 | virtual void ButtonPress(int id) = 0; 30 | virtual void ButtonUnpress(int id) = 0; 31 | virtual void SetButtonState(int id, CInputState state) = 0; 32 | int ActiveDropDown; 33 | int ActiveDropDownHover; 34 | 35 | // Check if an item is a particular type 36 | virtual bool IsButton(int id); 37 | virtual bool IsDropDown(int id); 38 | virtual bool IsTextInput(int id); 39 | virtual bool IsCheckBox(int id); 40 | 41 | // Closed flag 42 | bool IsClosed; 43 | 44 | protected: 45 | // Top left point of window 46 | POINT topLeft; 47 | 48 | // Window items 49 | map windowButtons; 50 | map textInputs; 51 | map checkBoxes; 52 | map dropDowns; 53 | map scrollBars; 54 | }; 55 | 56 | -------------------------------------------------------------------------------- /VatsimNAAATS/AcTargets.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include 4 | #include "Structures.h" 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | using namespace Gdiplus; 10 | using namespace EuroScopePlugIn; 11 | 12 | /// Drawing aircraft targets 13 | class CAcTargets 14 | { 15 | public: 16 | // Blink timers (for flashing white if critical conflict & halo around searched aircraft) 17 | static clock_t twoSecondTimer; 18 | static clock_t fiveSecondTimer; 19 | 20 | // Initialisation for button states 21 | static void Initialise(); 22 | 23 | // Render the airplane icon 24 | static void RenderTarget(Graphics* g, CDC* dc, CRadarScreen* screen, CRadarTarget* target, bool tagsOn, map* toggleData, bool halo, bool ptl, CSTCAStatus* status); 25 | 26 | // Render tags 27 | static POINT RenderTag(Graphics* g, CDC* dc, CRadarScreen* screen, CRadarTarget* target, pair* tagPosition, bool direction, CSTCAStatus* status, string asel); 28 | 29 | // Coordination tag item 30 | static void RenderCoordTagItem(CDC* dc, CRadarScreen* screen, string callsign, POINT tagPosition); 31 | 32 | // Draw selection halo 33 | static void RenderSelectionHalo(Graphics* g, CRadarScreen* screen, CRadarTarget* target); 34 | 35 | /// DIFFERENT TARGETS 36 | static void RenderADSBNoClrc(Graphics* g); // Diamond with a line through middle 37 | static void RenderRadarCoverage(Graphics* g); // Asterisk 38 | static void RenderClearanceWarning(Graphics* g); // Triangle 39 | static void RenderADSBCleared(Graphics* g); // Aeroplane icon 40 | 41 | // Aircraft search 42 | static string SearchedAircraft; 43 | 44 | // Fields 45 | static string OpenTrackingDialog; 46 | static map ButtonStates; 47 | }; 48 | -------------------------------------------------------------------------------- /VatsimNAAATS/DataHandler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "vector" 3 | #include "Structures.h" 4 | #include "EuroScopePlugIn.h" 5 | #include "Overlays.h" 6 | #include "Utils.h" 7 | #include "Logger.h" 8 | #include 9 | 10 | using namespace std; 11 | using namespace EuroScopePlugIn; 12 | 13 | class CDataHandler 14 | { 15 | public: 16 | // Check plugin version number 17 | static int CheckPluginVersion(CPlugIn* plugin); 18 | 19 | // Download nat track data 20 | static int PopulateLatestTrackData(CPlugIn* plugin); 21 | 22 | // Get flight data 23 | static CAircraftFlightPlan* GetFlightData(string callsign); 24 | static void GetFlightData(string callsign, CAircraftFlightPlan& fp); 25 | 26 | // Update a flight data object 27 | static int UpdateFlightData(CRadarScreen* screen, string callsign, bool updateRoute); 28 | 29 | // Create a new flight data object 30 | static int CreateFlightData(CRadarScreen* screen, string callsign); 31 | 32 | // Deletes a flight data object out of the flights map 33 | static int DeleteFlightData(string callsign); 34 | 35 | // Set route 36 | static int SetRoute(string callsign, vector* route, string track, CAircraftFlightPlan* copiedPlan = nullptr); 37 | 38 | /// vNAAATS network methods 39 | // Download aircraft data (single) 40 | static void DownloadNetworkAircraft(void* args); 41 | 42 | // Download all aircraft data 43 | static void GetAllNetworkAircraft(); 44 | 45 | // Post new aircraft data 46 | static void PostNetworkAircraft(void* args); 47 | 48 | // Update aircraft data 49 | static void UpdateNetworkAircraft(void* args); 50 | 51 | private: 52 | // Methods 53 | static int GetTrackSource(CPlugIn* plugin); // Event tracks or not 54 | 55 | // Version URL 56 | static const string PluginVersion; 57 | 58 | // NAT Track URL 59 | static const string TrackURL; 60 | static map flights; 61 | 62 | // vNAAATS API Links 63 | static const string TrackSource; 64 | static const string GetSingleAircraft; 65 | static const string FlightDataUpdate; 66 | static const string PostSingleAircraft; 67 | }; 68 | -------------------------------------------------------------------------------- /VatsimNAAATS/BaseWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "BaseWindow.h" 3 | #include "Styles.h" 4 | 5 | using namespace Colours; 6 | 7 | CBaseWindow::CBaseWindow(POINT topleft) { 8 | // Set top left 9 | topLeft = topleft; 10 | } 11 | 12 | POINT CBaseWindow::GetTopLeft() { 13 | return topLeft; 14 | } 15 | 16 | void CBaseWindow::MoveWindow(CRect area) { 17 | topLeft = { area.left, area.top }; 18 | } 19 | 20 | // TODO: Rewrite scrolling mechanic... again 21 | void CBaseWindow::Scroll(int id, POINT newPtr, POINT oldPtr) { 22 | // Get mouse delta 23 | double posDelta = 0.0; 24 | if (scrollBars[id].IsHorizontal) { 25 | posDelta = newPtr.x - oldPtr.x; 26 | } 27 | else { 28 | posDelta = newPtr.y - oldPtr.y; 29 | } 30 | 31 | // Get new grip position 32 | scrollBars[id].PositionDelta += posDelta; 33 | 34 | // Limit grip position 35 | if (scrollBars[id].PositionDelta < 0) { 36 | scrollBars[id].PositionDelta = 0; 37 | } 38 | if (scrollBars[id].PositionDelta > (scrollBars[id].FrameSize - 33 - scrollBars[id].GripSize)) { 39 | scrollBars[id].PositionDelta = scrollBars[id].FrameSize - 33 - scrollBars[id].GripSize; 40 | } 41 | 42 | // Get window position 43 | scrollBars[id].WindowPos = (scrollBars[id].PositionDelta / (scrollBars[id].FrameSize - 12 - scrollBars[id].GripSize)) * scrollBars[id].TotalScrollableArea; 44 | } 45 | 46 | string CBaseWindow::GetTextValue(int id) { 47 | if (textInputs.find(id) != textInputs.end()) { 48 | return textInputs.find(id)->second.Content; 49 | } 50 | else { 51 | return ""; 52 | } 53 | } 54 | 55 | bool CBaseWindow::IsButton(int id) { 56 | // If exists return true 57 | if (windowButtons.find(id) != windowButtons.end()) return true; 58 | return false; // It doesn't exist 59 | } 60 | 61 | bool CBaseWindow::IsDropDown(int id) { 62 | // If exists return true 63 | if (dropDowns.find(id) != dropDowns.end()) return true; 64 | return false; // It doesn't exist 65 | } 66 | 67 | bool CBaseWindow::IsTextInput(int id) { 68 | // If exists return true 69 | if (textInputs.find(id) != textInputs.end()) return true; 70 | return false; // It doesn't exist 71 | } 72 | 73 | bool CBaseWindow::IsCheckBox(int id) { 74 | // If exists return true 75 | if (checkBoxes.find(id) != checkBoxes.end()) return true; 76 | return false; // It doesn't exist 77 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VATSIM North Atlantic Advanced Air Traffic System 2 | ![vNAAATS Image](https://i.imgur.com/452ZeM2.png) 3 | 4 | vNAAATS is a plugin designed to revolutionise day-to-day oceanic operations on the VATSIM network. It simulates the GAATS+ HMI (Gander Automated Air Traffic System +) used by Oceanic controllers at Gander and Prestwick (Shanwick). The plugin supports track drawing, full clearance workflows, and a full conflict toolset for Oceanic controllers. In addition, it supports a CPDLC-esque exchange of data via datalink through natTrak. 5 | 6 | ### Main Features 7 | - Custom drawn oceanic tags with detailed mode and status indicators 8 | - Smart traffic filtering by area and altitude; oceanic controllers only see the aircraft relevant to them 9 | - NAT Track overlays and overview window 10 | - Smart route drawing function, interpolating NAT tracks as the aircraft's route if they are flying one 11 | - Lists: Inbound (showing direction of flight), Other, Conflicts 12 | - Sep tool showing potential conflicts for two aircraft presuming continuance on current heading 13 | - PIV (Path Intercept Vector) tool showing potential conflicts along two aircraft routes 14 | - RBL (Range Bearing Line) showing distance between two aircraft and indicating any conflicts, distance shown in minutes and miles 15 | - Halo and PTL (Projected Track Line) tools with ability to choose distance 16 | - Custom line ruler mechanic similar to default ES ruler 17 | - Grid display 18 | - Flight plan window with ability to share data between plugins 19 | - Probe tool to detect conflicts down a track before issuing an oceanic clearance 20 | - Controller notepad for general information 21 | - Recognition of aircraft equipment code to determine compatibility with ADS-B procedures and indicator to display whether aircraft is compatible 22 | - Saving of data 23 | - ... and more! 24 | 25 | ![Gander Logo](https://cdn.ganderoceanic.ca/resources/media/img/brand/bnr/ZQO_BNRSMALL_BLUE.png) 26 | ![vNAAATS Logo](https://cdn.ganderoceanic.ca/resources/media/img/vNAAATS-logo.png) 27 | 28 | Deleaker has helped me to make vNAAATS amazing by helping me expose the root causes of countless, irritating memory leaks. Without this outstanding piece of software, vNAAATS would be nowhere near as developed as it is right now. Go check out the VS extension here! http://deleaker.com/ 29 | -------------------------------------------------------------------------------- /VatsimNAAATS/MenuBar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "Structures.h" 8 | 9 | using namespace std; 10 | using namespace EuroScopePlugIn; 11 | using namespace Gdiplus; 12 | class CMenuBar 13 | { 14 | public: 15 | CMenuBar(); 16 | ~CMenuBar() {}; 17 | void RenderBar(CDC* dc, Graphics* g, CRadarScreen* screen, string asel); 18 | bool IsButtonPressed(int id); 19 | string GetDropDownValue(int id); 20 | map GetToggleButtons(); 21 | void SetButtonState(int id, CInputState state); 22 | CInputState GetButtonState(int id); 23 | void OnOverDropDownItem(int id); 24 | void SetDropDownValue(int id, int value); 25 | void MakeDropDownItems(int id); 26 | void SetTextInput(int id, string value); 27 | void ButtonDown(int id); 28 | void ButtonUp(int id); 29 | void ButtonPress(int id, int button, CRadarScreen* screen); 30 | void ButtonUnpress(int id, int button, CRadarScreen* screen); 31 | void GetSelectedTracks(vector& tracksVector); 32 | int ActiveDropDown; 33 | int ActiveDropDownHover; 34 | 35 | // Definitions 36 | static const int BTN_SETUP = 0; 37 | static const int BTN_NOTEPAD = 1; 38 | static const int BTN_ADSC = 2; 39 | static const int BTN_TCKINFO = 3; 40 | static const int BTN_MISC = 4; 41 | static const int BTN_MESSAGE = 5; 42 | static const int BTN_TAGS = 6; 43 | static const int BTN_FLIGHTPLAN = 7; 44 | static const int BTN_DETAILED = 8; 45 | static const int BTN_AREASEL = 9; 46 | static const int BTN_TCKCTRL = 10; 47 | static const int BTN_OVERLAYS = 11; 48 | static const int BTN_TYPESEL = 12; 49 | static const int BTN_ALTFILT = 13; 50 | static const int BTN_HALO = 14; 51 | static const int BTN_RBL = 15; 52 | static const int BTN_RINGS = 16; 53 | static const int BTN_QDM = 17; 54 | static const int BTN_PTL = 18; 55 | static const int BTN_PIV = 19; 56 | static const int BTN_GRID = 20; 57 | static const int BTN_SEP = 21; 58 | static const int BTN_QCKLOOK = 22; 59 | static const int BTN_PSSR = 23; 60 | static const int BTN_EXT = 24; 61 | static const int BTN_AUTOTAG = 25; 62 | static const int BTN_ALL = 26; 63 | static const int BTN_RTEDEL = 27; 64 | 65 | static const int DRP_AREASEL = 100; 66 | static const int DRP_TCKCTRL = 101; 67 | static const int DRP_OVERLAYS = 102; 68 | static const int DRP_TYPESEL = 103; 69 | 70 | static const int TXT_ALTFILT = 30; 71 | static const int ID_POS = 31; 72 | static const int TXT_SEARCH = 32; 73 | 74 | const int PANEL_SIZES[8] = { RECT1_WIDTH, RECT2_WIDTH, RECT3_WIDTH, RECT4_WIDTH, RECT5_WIDTH, RECT6_WIDTH, RECT7_WIDTH, RECT8_WIDTH }; 75 | 76 | map dropDowns; 77 | 78 | private: 79 | // Menu bar objects 80 | map buttons; 81 | map textInputs; 82 | map checkBoxes; 83 | map panels; 84 | }; 85 | 86 | -------------------------------------------------------------------------------- /VatsimNAAATS/OtherList.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "OtherList.h" 3 | #include "Constants.h" 4 | #include "Styles.h" 5 | 6 | using namespace Colours; 7 | 8 | vector COtherList::AircraftList; 9 | 10 | COtherList::COtherList(POINT topLeft) : CBaseList(topLeft) {} 11 | 12 | // TODO: implement expand/retract button 13 | void COtherList::RenderList(Graphics* g, CDC* dc, CRadarScreen* screen) { 14 | // Save context for later 15 | int sDC = dc->SaveDC(); 16 | 17 | // Brush 18 | SolidBrush brush(TextWhite); 19 | 20 | // Make rectangle 21 | Rect rectangle(topleft.x, topleft.y, LIST_OTHERS_WIDTH, 500); 22 | 23 | /// Make "Others" text 24 | // Font 25 | FontSelector::SelectMonoFont(15, dc); 26 | dc->SetTextColor(TextWhite.ToCOLORREF()); 27 | dc->SetTextAlign(TA_LEFT); 28 | 29 | // Get object area and add object to screen 30 | CRect area(topleft.x, topleft.y, topleft.x + LIST_OTHERS_WIDTH, topleft.y + 14); 31 | screen->AddScreenObject(LIST_OTHERS, "", area, true, ""); 32 | 33 | // Don't show size if none 34 | if (AircraftList.size() == 0) { 35 | dc->TextOutA(rectangle.X, rectangle.Y, "Others"); 36 | } 37 | else { 38 | dc->TextOutA(rectangle.X, rectangle.Y, string("Others (" + to_string(AircraftList.size()) + ")").c_str()); 39 | // Make dropdown button 40 | size_t textExtentY = dc->GetTextExtent("Others").cy; 41 | if (HideShowButton) { // If show 42 | Point btn[3] = { Point(rectangle.X + 140, rectangle.Y), 43 | Point(rectangle.X + 128, rectangle.Y + textExtentY - 2), 44 | Point(rectangle.X + 152, rectangle.Y + textExtentY - 2) }; 45 | g->FillPolygon(&brush, btn, 3); 46 | } 47 | else { // If hide 48 | Point btn[3] = { Point(rectangle.X + 140, rectangle.Y + textExtentY - 2), 49 | Point(rectangle.X + 128, rectangle.Y), 50 | Point(rectangle.X + 152, rectangle.Y) }; 51 | g->FillPolygon(&brush, btn, 3); 52 | } 53 | 54 | // Add the button 55 | CRect rect(rectangle.X + 128, rectangle.Y, rectangle.X + 152, rectangle.Y + textExtentY - 2); 56 | screen->AddScreenObject(LIST_OTHERS, "HIDESHOW", rect, false, ""); 57 | } 58 | 59 | // Text 60 | FontSelector::SelectATCFont(18, dc); 61 | dc->SetTextColor(TextWhite.ToCOLORREF()); 62 | dc->SetTextAlign(TA_LEFT); 63 | 64 | // Make text lines 65 | int offsetY = 14; 66 | int offsetX = 0; 67 | int idx = 1; 68 | 69 | // If list shown 70 | if (HideShowButton) { 71 | for (vector::iterator cs = AircraftList.begin(); cs != AircraftList.end(); cs++) { 72 | // Draw number 73 | string line = to_string(idx); 74 | dc->TextOutA(rectangle.X + offsetX, rectangle.Y + offsetY, line.c_str()); 75 | offsetX += 35; 76 | 77 | // Draw callsign 78 | line = *cs; 79 | dc->TextOutA(rectangle.X + offsetX, rectangle.Y + offsetY, line.c_str()); 80 | 81 | // Offset the y index and reset the X offset 82 | offsetY += 18; 83 | offsetX = 0; 84 | 85 | // Increment 86 | idx++; 87 | } 88 | } 89 | 90 | // Cleanup 91 | DeleteObject(&brush); 92 | } -------------------------------------------------------------------------------- /VatsimNAAATS/ConflictDetection.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "EuroScopePlugIn.h" 3 | #include 4 | #include "Constants.h" 5 | #include "Utils.h" 6 | #include "Structures.h" 7 | #include "RoutesHelper.h" 8 | #include "DataHandler.h" 9 | #include "Styles.h" 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | using namespace Colours; 15 | using namespace Gdiplus; 16 | using namespace EuroScopePlugIn; 17 | 18 | class CConflictDetection 19 | { 20 | public: 21 | // PIV 22 | static vector PIVLocations1; 23 | static vector PIVLocations2; 24 | static vector PIVRoute1; 25 | static vector PIVRoute2; 26 | static vector PIVSeparationStatuses; 27 | static map* aircraftOnScreen; 28 | 29 | // STCA 30 | static vector CurrentSTCA; 31 | 32 | // Range Bearing Line tool 33 | static void RBLTool(CDC* dc, Graphics* g, CRadarScreen* screen, string target1, string target2); 34 | 35 | // Separation vector tool 36 | static void SepTool(CDC* dc, Graphics* g, CRadarScreen* screen, string targetA, string targetB); 37 | 38 | // Path Intercept Vector tool 39 | static void PIVTool(CRadarScreen* screen, string targetA, string targetB); 40 | 41 | // Path Intercept Vector tool 42 | static void RenderPIV(CDC* dc, Graphics* g, CRadarScreen* screen, string targetA, string targetB); 43 | 44 | // STCA (run every 10s) 45 | static void CheckSTCA(CRadarScreen* screen, CRadarTarget* target, map* onScreenAircraft); 46 | 47 | // Probe tool 48 | static bool ProbeTool(CRadarScreen* screen, string callsign, map>* statuses, CAircraftFlightPlan* copy = nullptr); 49 | 50 | private: 51 | // Separation values 52 | static const int SEPV_LOW = 1000; // Subtract 150 otherwise it's way too sensitive 53 | static const int SEPV_HIGH = 1900; 54 | static const int SEPV_SUPERSONIC = 3900; 55 | static const int SEPLAT_NONREDUCED = 60; // NM 56 | static const int SEPLAT_REDUCED = 19; // NM 57 | static const int SEPLON_REDUCED = 15; // NM 58 | static const int SEPLON_REDUCEDWARN = 30; // NM 59 | static const int SEPLON_NONRED_SAME_WARN = 15; // Minutes 60 | static const int SEPLON_NONRED_SAME = 10; // Minutes 61 | static const int SEPLON_NONRED_X_WARN = 20; // Minutes 62 | static const int SEPLON_NONRED_X = 15; // NM 63 | 64 | // Detect a conflict status between two aircraft (current or future) 65 | static CSepStatus DetectStatus(CRadarScreen* screen, CAircraftStatus* aircraftA, CAircraftStatus* aircraftB); 66 | 67 | // Get an aircraft's status along its route 68 | static vector GetStatusesAlongRoute(CRadarScreen* screen, string callsign, int groundSpeed, int altitude, int pivID); 69 | 70 | // Get statuses along the route points 71 | static vector GetStatusesAlongRoutePoints(CRadarScreen* screen, string callsign, int groundSpeed, int altitude); 72 | 73 | // Mach number technique 74 | static int MachNumberTechnique(CRadarScreen* screen, CAircraftStatus* aircraftA, CAircraftStatus* aircraftB, string point); 75 | }; 76 | 77 | -------------------------------------------------------------------------------- /VatsimNAAATS/ConflictList.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Constants.h" 3 | #include "Styles.h" 4 | #include "Utils.h" 5 | #include "ConflictList.h" 6 | 7 | using namespace Colours; 8 | 9 | CConflictList::CConflictList(POINT topLeft) : CBaseList(topLeft) {} 10 | 11 | // TODO: implement expand/retract button 12 | void CConflictList::RenderList(Graphics* g, CDC* dc, CRadarScreen* screen) { 13 | // Save context for later 14 | int sDC = dc->SaveDC(); 15 | 16 | // Make rectangle 17 | Rect rectangle(topleft.x, topleft.y, LIST_CONFLICT_WIDTH, 500); 18 | 19 | /// Make "Conflict" text 20 | // Font 21 | FontSelector::SelectMonoFont(15, dc); 22 | dc->SetTextColor(TextWhite.ToCOLORREF()); 23 | dc->SetTextAlign(TA_LEFT); 24 | 25 | // Don't show size if none 26 | if (CConflictDetection::CurrentSTCA.size() == 0) { 27 | dc->TextOutA(rectangle.X, rectangle.Y, "Conflict"); 28 | } 29 | else { 30 | dc->TextOutA(rectangle.X, rectangle.Y, string("Conflict (" + to_string(CConflictDetection::CurrentSTCA.size()) + ")").c_str()); 31 | } 32 | 33 | // Text 34 | FontSelector::SelectATCFont(18, dc); 35 | dc->SetTextAlign(TA_LEFT); 36 | 37 | // Make text lines 38 | int offsetY = 14; 39 | int offsetX = 0; 40 | for (auto item = CConflictDetection::CurrentSTCA.begin(); item != CConflictDetection::CurrentSTCA.end(); item++) { 41 | // Get flight plans 42 | CAircraftFlightPlan fp1; 43 | CAircraftFlightPlan fp2; 44 | CDataHandler::GetFlightData(item->CallsignA, fp1); 45 | CDataHandler::GetFlightData(item->CallsignB, fp2); 46 | 47 | // Pick text colour 48 | COLORREF textColour; 49 | if (item->ConflictStatus == CConflictStatus::CRITICAL) { 50 | // Select red because critical conflict 51 | textColour = CriticalRedLight.ToCOLORREF(); 52 | } 53 | else { 54 | // Select yellow because warning 55 | textColour = WarningYellow.ToCOLORREF(); 56 | } 57 | 58 | // Text colour 59 | dc->SetTextColor(textColour); 60 | 61 | // Draw callsign A 62 | string line = item->CallsignA; 63 | dc->TextOutA(rectangle.X + offsetX, rectangle.Y + offsetY, line.c_str()); 64 | offsetX += 80; 65 | 66 | // Draw callsign B 67 | line = item->CallsignB; 68 | dc->TextOutA(rectangle.X + offsetX, rectangle.Y + offsetY, line.c_str()); 69 | offsetX += 90; 70 | 71 | // Draw status 72 | if (fp1.IsEquipped && fp2.IsEquipped) { 73 | if (item->ConflictStatus == CConflictStatus::WARNING) { // Warning 74 | line = "W" + to_string(item->DistanceAsNM); 75 | } 76 | else { // Critical 77 | line = "C" + to_string(item->DistanceAsNM); 78 | } 79 | } 80 | else { 81 | if (item->ConflictStatus == CConflictStatus::WARNING) { // Warning 82 | line = "W" + to_string(item->DistanceAsTime) + "*"; 83 | } 84 | else { // Critical 85 | line = "C" + to_string(item->DistanceAsTime) + "*"; 86 | } 87 | } 88 | 89 | dc->TextOutA(rectangle.X + offsetX, rectangle.Y + offsetY, line.c_str()); 90 | 91 | // Offset the y index and reset the X offset 92 | offsetY += 18; 93 | offsetX = 0; 94 | } 95 | 96 | // Get object area and add object to screen 97 | CRect area(topleft.x, topleft.y, topleft.x + LIST_CONFLICT_WIDTH, topleft.y + 14); 98 | screen->AddScreenObject(LIST_CONFLICT, "", area, true, ""); 99 | } -------------------------------------------------------------------------------- /VatsimNAAATS/RadarDisplay.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "InboundList.h" 8 | #include "Structures.h" 9 | #include "OtherList.h" 10 | #include "ConflictList.h" 11 | #include "RCLList.h" 12 | #include "MenuBar.h" 13 | #include "NotePad.h" 14 | #include "EuroScopePlugIn.h" 15 | #include "TrackInfoWindow.h" 16 | #include "FlightPlanWindow.h" 17 | #include "MessageWindow.h" 18 | 19 | using namespace std; 20 | using namespace EuroScopePlugIn; 21 | 22 | // Main radar display 23 | class CRadarDisplay : public CRadarScreen 24 | { 25 | public: 26 | // Constructor & Destructor 27 | CRadarDisplay(); 28 | virtual ~CRadarDisplay(); 29 | 30 | // Custom methods 31 | void PopulateProgramData(); 32 | 33 | // Public properties 34 | CPosition RulerPoint1; 35 | CPosition RulerPoint2; 36 | double RefreshResolution = 0.2; 37 | 38 | // Inherited methods 39 | void OnRefresh(HDC hDC, int Phase); 40 | void OnRadarTargetPositionUpdate(CRadarTarget RadarTarget); 41 | void OnFlightPlanDisconnect(CFlightPlan FlightPlan); 42 | void OnMoveScreenObject(int ObjectType, const char* sObjectId, POINT Pt, RECT Area, bool Released); 43 | void OnOverScreenObject(int ObjectType, const char* sObjectId, POINT Pt, RECT Area); 44 | void OnClickScreenObject(int ObjectType, const char* sObjectId, POINT Pt, RECT Area, int Button); 45 | void OnButtonDownScreenObject(int ObjectType, const char* sObjectId, POINT Pt, RECT Area, int Button); 46 | void OnButtonUpScreenObject(int ObjectType, const char* sObjectId, POINT Pt, RECT Area, int Button); 47 | void OnFunctionCall(int FunctionId, const char* sItemString, POINT Pt, RECT Area); 48 | void OnDoubleClickScreenObject(int ObjectType, const char* sObjectId, POINT Pt, RECT Area, int Button); 49 | void OnAsrContentToBeSaved(void); 50 | void OnAsrContentLoaded(bool Loaded); 51 | static void CursorStateUpdater(void* args); // Asynchronous loop 52 | 53 | inline void OnAsrContentToBeClosed(void) 54 | { 55 | // Manually call save 56 | OnAsrContentToBeSaved(); 57 | appCursor->isESClosed = true; 58 | } 59 | 60 | private: 61 | // Cursor position structure for async 62 | struct CAppCursor { 63 | CRadarDisplay* screen; 64 | POINT position; // Screen coordinates 65 | CPosition latLonPosition; // Lat lon 66 | int button; 67 | clock_t singleClickTimer = 0; // activate on every single click to detect double click 68 | bool isDoubleClick = false; 69 | bool isESClosed = false; 70 | }; 71 | pair screenResolution; 72 | CAppCursor* appCursor = new CAppCursor(); // Constantly being updated 73 | POINT mousePointer; // Updated on screen object actions only 74 | clock_t fiveSecondTimer; 75 | clock_t tenSecondTimer; 76 | clock_t thirtySecondTimer; 77 | bool aselDetailed; 78 | map aircraftOnScreen; 79 | map menuFields; 80 | string asel = ""; 81 | map> tagStatuses; 82 | string aircraftSel1 = ""; // For use in conflict tools 83 | string aircraftSel2 = ""; // " 84 | CMenuBar* menuBar; 85 | CInboundList* inboundList; 86 | COtherList* otherList; 87 | //CRCLList* rclList; 88 | CConflictList* conflictList; 89 | CTrackInfoWindow* trackWindow = nullptr; 90 | CFlightPlanWindow* fltPlnWindow = nullptr; 91 | CMessageWindow* msgWindow = nullptr; 92 | CNotePad* npWindow = nullptr; 93 | }; 94 | 95 | -------------------------------------------------------------------------------- /VatsimNAAATS/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Logger.h" 3 | 4 | string CLogger::logFilePath = ""; 5 | bool CLogger::initialised = false; 6 | bool CLogger::initialisedAc = false; 7 | 8 | void CLogger::Log(CLogType type, string text, string invokedBy) { 9 | if (DEBUG_MODE) { 10 | // Prefix 11 | string prefix = GeneratePrefix(type); 12 | 13 | // Format invokedBy if not an empty string 14 | invokedBy = invokedBy != "" ? "[" + invokedBy + "] " : ""; 15 | 16 | // Open, write then close 17 | ofstream log; 18 | if (!initialised) { // Overwrite first time 19 | log.open(logFilePath.c_str()); 20 | initialised = true; 21 | } 22 | else { // Append thereafter 23 | log.open(logFilePath.c_str(), std::ios_base::app | std::ios_base::out); 24 | } 25 | log << prefix.c_str() << invokedBy << text.c_str() << "\n"; 26 | log.close(); 27 | } 28 | } 29 | 30 | void CLogger::DebugLog(CRadarScreen* screen, string text) { 31 | screen->GetPlugIn()->DisplayUserMessage("vNAAATS", "Log", text.c_str(), true, true, true, true, true); 32 | } 33 | 34 | void CLogger::LogAircraftDebugInfo(string text) // Debug logger for some raw AC data 35 | { 36 | // Open, write then close 37 | ofstream log; 38 | if (!initialisedAc) { // Overwrite first time 39 | log.open(CUtils::DllPath + "\\raw_ac_data.txt"); 40 | initialisedAc = true; 41 | } 42 | else { // Append thereafter 43 | log.open(CUtils::DllPath + "\\raw_ac_data.txt", std::ios_base::app | std::ios_base::out); 44 | } 45 | log << text.c_str() << "\n"; 46 | log.close(); 47 | } 48 | 49 | void CLogger::InstantiateLogFile() { 50 | // Instantiate file path 51 | logFilePath = CUtils::DllPath + "\\vNAAATS.log"; 52 | 53 | // Get system memory size in MB 54 | uint64_t memKB; 55 | GetPhysicallyInstalledSystemMemory(&memKB); 56 | long installedMemoryMB = memKB / 1000; 57 | 58 | // Build output 59 | string output; 60 | output += "***** LOG INITIALISED FOR vNAAATS VERSION "; 61 | output += PLUGIN_VERSION; 62 | output += " *****\n"; 63 | output += "COPYRIGHT "; 64 | output += PLUGIN_COPYRIGHT; 65 | output += "\nRAM (MB): "; 66 | output += to_string(installedMemoryMB); 67 | output += "\nAlpha?:"; 68 | output += IS_ALPHA ? " TRUE" : " FALSE"; 69 | output += "\n----------------------------------"; 70 | 71 | // Write 72 | Log(CLogType::INIT, output); 73 | } 74 | 75 | string CLogger::GeneratePrefix(CLogType type) { 76 | // This will store the prefix 77 | string prefix = "["; 78 | 79 | // Date string (incl. milliseconds) 80 | SYSTEMTIME t; 81 | GetSystemTime(&t); 82 | string strTime; 83 | strTime += CUtils::PadWithZeros(2, t.wHour); 84 | strTime += ":"; 85 | strTime += CUtils::PadWithZeros(2, t.wMinute); 86 | strTime += ":"; 87 | strTime += CUtils::PadWithZeros(2, t.wSecond); 88 | strTime += "."; 89 | strTime += to_string(t.wMilliseconds); 90 | 91 | // Begin 92 | switch (type) { 93 | case CLogType::INIT: 94 | prefix += "INIT "; 95 | break; 96 | case CLogType::NORM: 97 | prefix += "LOG "; 98 | break; 99 | case CLogType::WARN: 100 | prefix += "WARN "; 101 | break; 102 | case CLogType::ERR: 103 | prefix += "ERR "; 104 | break; 105 | case CLogType::EXC: 106 | prefix += "EXC "; 107 | break; 108 | } 109 | 110 | // Append date/time and closing bracket 111 | prefix += strTime; 112 | prefix += "] "; 113 | 114 | // Return the prefix 115 | return prefix; 116 | } -------------------------------------------------------------------------------- /VatsimNAAATS/NotePad.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "NotePad.h" 3 | #include "Constants.h" 4 | #include "Styles.h" 5 | 6 | using namespace EuroScopePlugIn; 7 | using namespace Gdiplus; 8 | using namespace Colours; 9 | 10 | const int CNotePad::BTN_CLOSE = 0; 11 | const int CNotePad::BTN_SAVE = 1; 12 | 13 | CNotePad::CNotePad(POINT topLeft, POINT topLeftList) : CBaseWindow(topLeft), CBaseList(topLeftList) { 14 | // Make buttons 15 | MakeWindowItems(); 16 | 17 | // Close by default 18 | IsClosed = true; 19 | } 20 | 21 | void CNotePad::MakeWindowItems() { 22 | windowButtons[BTN_CLOSE] = CWinButton(BTN_CLOSE, WIN_NOTEPAD, "Close", CInputState::INACTIVE); 23 | windowButtons[BTN_SAVE] = CWinButton(BTN_SAVE, WIN_NOTEPAD, "Save", CInputState::DISABLED); 24 | } 25 | 26 | void CNotePad::RenderWindow(CDC* dc, Graphics* g, CRadarScreen* screen) { 27 | // Save device context 28 | int iDC = dc->SaveDC(); 29 | 30 | // Create brushes 31 | CBrush darkerBrush(ScreenBlue.ToCOLORREF()); 32 | CBrush lighterBrush(WindowBorder.ToCOLORREF()); 33 | CBrush evenDarkerBrush(ButtonPressed.ToCOLORREF()); 34 | 35 | // Select title font 36 | FontSelector::SelectNormalFont(16, dc); 37 | dc->SetTextColor(Black.ToCOLORREF()); 38 | dc->SetTextAlign(TA_CENTER); 39 | 40 | // Create base window rectangle 41 | CRect windowRect(topLeft.x, topLeft.y, topLeft.x + WINSZ_NP_WIDTH, topLeft.y + WINSZ_NP_HEIGHT); 42 | dc->FillRect(windowRect, &darkerBrush); 43 | 44 | // Create titlebar 45 | CRect titleRect(windowRect.left, windowRect.top, windowRect.left + WINSZ_NP_WIDTH, windowRect.top + WINSZ_TITLEBAR_HEIGHT); 46 | dc->FillRect(titleRect, &lighterBrush); 47 | dc->DrawEdge(titleRect, EDGE_RAISED, BF_BOTTOM); 48 | dc->TextOutA(titleRect.left + (WINSZ_NP_WIDTH / 2), titleRect.top + (WINSZ_TITLEBAR_HEIGHT / 7), "Note Pad"); 49 | 50 | // Create content panel 51 | CRect content(windowRect.left + 5, titleRect.bottom + 5, windowRect.right - 5, windowRect.bottom - 40); 52 | dc->Draw3dRect(content, BevelDark.ToCOLORREF(), BevelLight.ToCOLORREF()); 53 | InflateRect(content, -1, -1); 54 | dc->Draw3dRect(content, BevelDark.ToCOLORREF(), BevelLight.ToCOLORREF()); 55 | 56 | // Add screen objects 57 | screen->AddScreenObject(WINDOW, "WIN_NP", windowRect, false, ""); // So that we can't click anything under the notepad window 58 | screen->AddScreenObject(WINDOW, "NOTEPAD", titleRect, true, ""); // Movable 59 | 60 | /// Draw buttons 61 | // Refresh button 62 | CCommonRenders::RenderButton(dc, screen, { windowRect.left + 10, content.bottom + 5 }, 55, 30, &windowButtons.at(BTN_CLOSE)); 63 | // Close button 64 | CCommonRenders::RenderButton(dc, screen, { windowRect.right - 65, content.bottom + 5 }, 55, 30, &windowButtons.at(BTN_SAVE)); 65 | 66 | // Create borders 67 | dc->DrawEdge(windowRect, EDGE_SUNKEN, BF_RECT); 68 | InflateRect(windowRect, 1, 1); 69 | dc->Draw3dRect(windowRect, WindowBorder.ToCOLORREF(), WindowBorder.ToCOLORREF()); 70 | InflateRect(windowRect, 1, 1); 71 | dc->DrawEdge(windowRect, EDGE_RAISED, BF_RECT); 72 | 73 | // Cleanup 74 | DeleteObject(darkerBrush); 75 | DeleteObject(lighterBrush); 76 | 77 | // Restore device context 78 | dc->RestoreDC(iDC); 79 | } 80 | 81 | void CNotePad::RenderList(Graphics* g, CDC* dc, CRadarScreen* screen) { 82 | 83 | } 84 | 85 | void CNotePad::ButtonDown(int id) { 86 | // Press button 87 | windowButtons.find(id)->second.State = CInputState::ACTIVE; 88 | } 89 | 90 | void CNotePad::ButtonUp(int id, CRadarScreen* screen) { 91 | // Unpress the button 92 | windowButtons.find(id)->second.State = CInputState::INACTIVE; 93 | } 94 | 95 | void CNotePad::ButtonPress(int id) { 96 | 97 | } 98 | 99 | void CNotePad::ButtonUnpress(int id) { 100 | 101 | } 102 | 103 | void CNotePad::SetButtonState(int id, CInputState state) { 104 | 105 | } -------------------------------------------------------------------------------- /VatsimNAAATS/InboundList.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "InboundList.h" 3 | #include "Constants.h" 4 | #include "Styles.h" 5 | #include "Utils.h" 6 | #include 7 | #include 8 | 9 | using namespace Colours; 10 | 11 | vector CInboundList::AircraftList; 12 | 13 | CInboundList::CInboundList(POINT topLeft) : CBaseList(topLeft) { 14 | 15 | } 16 | 17 | // TODO: Sort items by time, earliest first 18 | void CInboundList::RenderList(Graphics* g, CDC* dc, CRadarScreen* screen) 19 | { 20 | // Save context for later 21 | int sDC = dc->SaveDC(); 22 | 23 | // Brush 24 | SolidBrush brush(TextWhite); 25 | 26 | // Make rectangle 27 | Rect rectangle(topleft.x, topleft.y, LIST_INBOUND_WIDTH, 500); 28 | 29 | // Text 30 | FontSelector::SelectATCFont(18, dc); 31 | dc->SetTextColor(TextWhite.ToCOLORREF()); 32 | dc->SetTextAlign(TA_LEFT); 33 | 34 | // Make inbound lines 35 | int offsetY = 14; 36 | int offsetX = 18; 37 | int idx = 0; 38 | 39 | // Draw planes if not hidden 40 | if (HideShowButton) { 41 | for (vector::iterator ac = AircraftList.begin(); ac != AircraftList.end(); ac++) { 42 | // Direction arrow (Shanwick) 43 | if (ac->Direction == false) { 44 | SolidBrush brush(TextWhite); 45 | Point points[3] = { Point(rectangle.X + 10, rectangle.Y + (offsetY + 4)), 46 | Point(rectangle.X + 10, rectangle.Y + (offsetY + 4) + 10), 47 | Point(rectangle.X, rectangle.Y + (offsetY + 4) + 5) }; 48 | g->FillPolygon(&brush, points, 3); 49 | } 50 | // Draw callsign 51 | string line = string(ac->Callsign); 52 | dc->TextOutA(rectangle.X + offsetX, rectangle.Y + offsetY, line.c_str()); 53 | offsetX += 140; 54 | 55 | // Draw entry point 56 | line = CUtils::ConvertCoordinateFormat(ac->Point, 0); 57 | dc->TextOutA(rectangle.X + offsetX, rectangle.Y + offsetY, line.c_str()); 58 | offsetX += 70; 59 | 60 | // Draw estimated time 61 | line = ac->Estimate; 62 | dc->TextOutA(rectangle.X + offsetX, rectangle.Y + offsetY, line.c_str()); 63 | offsetX += 45; 64 | 65 | // Draw altitude 66 | line = to_string(ac->FinalAltitude / 100); 67 | dc->TextOutA(rectangle.X + offsetX, rectangle.Y + offsetY, line.c_str()); 68 | offsetX += 50; 69 | 70 | // Draw destination 71 | line = string(ac->Destination); 72 | dc->TextOutA(rectangle.X + offsetX, rectangle.Y + offsetY, line.c_str()); 73 | offsetX += 45; 74 | 75 | // Direction arrow (Gander) 76 | if (ac->Direction == true) { 77 | SolidBrush brush(TextWhite); 78 | Point points[3] = { Point(rectangle.X + offsetX, rectangle.Y + (offsetY + 4)), 79 | Point(rectangle.X + offsetX, rectangle.Y + (offsetY + 4) + 10), 80 | Point(rectangle.X + offsetX + 10, rectangle.Y + (offsetY + 4) + 5) }; 81 | g->FillPolygon(&brush, points, 3); 82 | } 83 | 84 | // Offset the y index and reset the X offset 85 | offsetY += 18; 86 | offsetX = 18; 87 | 88 | // Increment 89 | idx++; 90 | } 91 | } 92 | 93 | // Get object area and add object to screen 94 | CRect area(topleft.x, topleft.y, topleft.x + LIST_INBOUND_WIDTH, topleft.y + 14); 95 | screen->AddScreenObject(LIST_INBOUND, "", area, true, ""); 96 | 97 | /// Make "Inbound" text 98 | // Font 99 | FontSelector::SelectMonoFont(15, dc); 100 | dc->SetTextColor(TextWhite.ToCOLORREF()); 101 | dc->SetTextAlign(TA_LEFT); 102 | // Draw header but don't show size if none 103 | if (AircraftList.size() == 0) { 104 | dc->TextOutA(rectangle.X, rectangle.Y, "Inbound"); 105 | } 106 | else { 107 | dc->TextOutA(rectangle.X, rectangle.Y, string("Inbound (" + to_string(AircraftList.size()) + ")").c_str()); 108 | // Make dropdown button 109 | size_t textExtentY = dc->GetTextExtent("Inbound").cy; 110 | if (HideShowButton) { // If show 111 | Point btn[3] = { Point(rectangle.X + 140, rectangle.Y), 112 | Point(rectangle.X + 128, rectangle.Y + textExtentY - 2), 113 | Point(rectangle.X + 152, rectangle.Y + textExtentY - 2) }; 114 | g->FillPolygon(&brush, btn, 3); 115 | } 116 | else { // If hide 117 | Point btn[3] = { Point(rectangle.X + 140, rectangle.Y + textExtentY - 2), 118 | Point(rectangle.X + 128, rectangle.Y), 119 | Point(rectangle.X + 152, rectangle.Y) }; 120 | g->FillPolygon(&brush, btn, 3); 121 | } 122 | 123 | // Add the button 124 | CRect rect(rectangle.X + 128, rectangle.Y, rectangle.X + 152, rectangle.Y + textExtentY - 2); 125 | screen->AddScreenObject(LIST_INBOUND, "HIDESHOW", rect, false, ""); 126 | } 127 | 128 | // Cleanup 129 | DeleteObject(&brush); 130 | 131 | // Restore device context 132 | dc->RestoreDC(sDC); 133 | } 134 | -------------------------------------------------------------------------------- /VatsimNAAATS/Styles.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "Constants.h" 4 | #include 5 | #include 6 | #include "Utils.h" 7 | #include "Logger.h" 8 | 9 | using namespace Gdiplus; 10 | 11 | // Colours for the program 12 | namespace Colours { 13 | const Color TextWhite(255, 255, 255); 14 | const Color Disabled(164, 185, 215); 15 | const Color Black(0, 0, 0); 16 | const Color Grey(237, 237, 237); 17 | const Color DarkGrey(182, 182, 182); 18 | const Color TargetOrange(255, 128, 0); 19 | const Color TargetBlue(130, 175, 192); 20 | const Color LightGreen(81, 188, 161); 21 | const Color ScreenBlue(59, 110, 179); 22 | const Color LightBackground(165, 199, 249); 23 | const Color NoReadBk(254, 255, 199 ); 24 | const Color RouteBox(195, 219, 255); 25 | const Color BevelLight(110, 149, 203); 26 | const Color BevelDark(41, 80, 133); 27 | const Color GreenBevelLight(76, 191, 196); 28 | const Color GreenBevelDark(33, 120, 144); 29 | const Color ButtonPressed(45, 69, 90); 30 | const Color WindowBorder(187, 214, 238); 31 | const Color WarningYellow(240, 231, 76); 32 | const Color CriticalRed(195, 67, 67); 33 | const Color CriticalRedLight(225, 96, 96); 34 | const Color NoClearance(198, 74, 255); 35 | } 36 | 37 | // Fonts 38 | class FontSelector 39 | { 40 | public: 41 | static int InitialiseFonts() { 42 | // So that fonts are only ever initialised once 43 | if (fontsInitialised) return 0; 44 | 45 | LOGFONT lFont; 46 | 47 | // Get face for normal font 48 | memset(&lFont, 0, sizeof(LOGFONT)); 49 | strcpy_s(lFont.lfFaceName, _T("Arial")); 50 | // Normal weight 51 | lFont.lfWeight = FW_SEMIBOLD; 52 | // Size 14 53 | lFont.lfHeight = 14; 54 | normalFont14.CreateFontIndirect(&lFont); 55 | // Size 15 56 | lFont.lfHeight = 15; 57 | normalFont15.CreateFontIndirect(&lFont); 58 | // Size 16 59 | lFont.lfHeight = 16; 60 | normalFont16.CreateFontIndirect(&lFont); 61 | // Size 30 62 | lFont.lfHeight = 30; 63 | normalFont30.CreateFontIndirect(&lFont); 64 | 65 | // Get the face 66 | strcpy_s(lFont.lfFaceName, _T("Lucida Console")); 67 | // Normal weight 68 | lFont.lfWeight = FW_SEMIBOLD; 69 | // Size 12 70 | lFont.lfHeight = 12; 71 | monoFont12.CreateFontIndirect(&lFont); 72 | // Size 14 73 | lFont.lfHeight = 14; 74 | monoFont14.CreateFontIndirect(&lFont); 75 | // Size 15 76 | lFont.lfHeight = 15; 77 | monoFont15.CreateFontIndirect(&lFont); 78 | 79 | // Get for ATC font 80 | AddFontResource((LPCSTR)(CUtils::DllPath + "\\vNAAATS.ttf").c_str()); 81 | strcpy_s(lFont.lfFaceName, _T("vNAAATS")); 82 | // Normal weight 83 | lFont.lfWeight = FW_REGULAR; 84 | // Size 14 85 | lFont.lfHeight = 14; 86 | atcFont14.CreateFontIndirect(&lFont); 87 | // Size 15 88 | lFont.lfHeight = 15; 89 | atcFont15.CreateFontIndirect(&lFont); 90 | // Size 16 91 | lFont.lfHeight = 16; 92 | atcFont16.CreateFontIndirect(&lFont); 93 | // Size 18 94 | lFont.lfHeight = 18; 95 | atcFont18.CreateFontIndirect(&lFont); 96 | 97 | // Initialised 98 | fontsInitialised = true; 99 | CLogger::Log(CLogType::NORM, "Fonts initialised.", "FontSelector"); 100 | return 0; 101 | } 102 | 103 | static void SelectNormalFont(int size, CDC* dc) { 104 | // Select font based on font size 105 | if (size == 14) { 106 | dc->SelectObject(normalFont14); 107 | } 108 | else if (size == 15) { 109 | dc->SelectObject(normalFont15); 110 | } 111 | else if (size == 16) { 112 | dc->SelectObject(normalFont16); 113 | } 114 | else if (size == 30) { 115 | dc->SelectObject(normalFont30); 116 | } 117 | } 118 | 119 | static void SelectMonoFont(int size, CDC* dc) { 120 | // Select font based on font size 121 | if (size == 12) { 122 | dc->SelectObject(monoFont12); 123 | } 124 | else if (size == 14) { 125 | dc->SelectObject(monoFont14); 126 | } 127 | else if (size == 15) { 128 | dc->SelectObject(monoFont15); 129 | } 130 | } 131 | 132 | static void SelectATCFont(int size, CDC* dc) { 133 | // Select font based on font size 134 | if (size == 14) { 135 | dc->SelectObject(atcFont14); 136 | } 137 | if (size == 15) { 138 | dc->SelectObject(atcFont15); 139 | } 140 | else if (size == 16) { 141 | dc->SelectObject(atcFont16); 142 | } 143 | else if (size == 18) { 144 | dc->SelectObject(atcFont18); 145 | } 146 | } 147 | 148 | private: 149 | static CFont normalFont14; 150 | static CFont normalFont15; 151 | static CFont normalFont16; 152 | static CFont normalFont30; 153 | static CFont monoFont12; 154 | static CFont monoFont14; 155 | static CFont monoFont15; 156 | static CFont atcFont14; 157 | static CFont atcFont15; 158 | static CFont atcFont16; 159 | static CFont atcFont18; 160 | static bool fontsInitialised; // So that we don't try and re-initialise all the fonts 161 | }; -------------------------------------------------------------------------------- /VatsimNAAATS/Overlays.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Overlays.h" 3 | 4 | COverlayType COverlays::CurrentType = COverlayType::TCKS_ALL; 5 | 6 | void COverlays::ShowCurrentOverlay(CDC* dc, Graphics* g, CRadarScreen* screen, CMenuBar* menubar) { 7 | // Render the tracks path 8 | CCommonRenders::RenderTracks(dc, g, screen, CurrentType, menubar); 9 | } 10 | 11 | // Show and hide the grid reference and waypoints 12 | void COverlays::ShowHideGridReference(CRadarScreen* screen, bool show) { 13 | screen->GetPlugIn()->SelectActiveSectorfile(); 14 | 15 | CSectorElement gridElement; 16 | for (gridElement = screen->GetPlugIn()->SectorFileElementSelectFirst(EuroScopePlugIn::SECTOR_ELEMENT_GEO); 17 | gridElement.IsValid(); 18 | gridElement = screen->GetPlugIn()->SectorFileElementSelectNext(gridElement, EuroScopePlugIn::SECTOR_ELEMENT_GEO)) 19 | { 20 | string t = gridElement.GetName(); 21 | if (t == "CZQO Landmark Positional Grid Reference" || t == "EGGX Landmark Positional Grid Reference") { 22 | break; 23 | } 24 | } 25 | 26 | // Show the grid 27 | screen->ShowSectorFileElement(gridElement, gridElement.GetComponentName(0), show); 28 | 29 | CSectorElement gridTextElement; 30 | for (gridTextElement = screen->GetPlugIn()->SectorFileElementSelectFirst(EuroScopePlugIn::SECTOR_ELEMENT_FREE_TEXT); 31 | gridTextElement.IsValid(); 32 | gridTextElement = screen->GetPlugIn()->SectorFileElementSelectNext(gridTextElement, EuroScopePlugIn::SECTOR_ELEMENT_FREE_TEXT)) 33 | { 34 | string t = gridTextElement.GetName(); 35 | if (t.find("CZQO Grid Reference Numbers.") != string::npos || t.find("EGGX Grid Reference Numbers.") != string::npos) { 36 | break; 37 | } 38 | } 39 | 40 | // Show the grid 41 | screen->ShowSectorFileElement(gridTextElement, gridElement.GetComponentName(0), show); 42 | 43 | /*if (show) { // If to be shown 44 | // Get sector file and element 45 | 46 | CSectorElement grid(screen->GetPlugIn()->SectorFileElementSelectFirst(13)); 47 | string gridName = string(grid.GetName()); 48 | 49 | // Find the grid 50 | while (gridName != "CZQO Landmark Positional Grid Reference" || gridName != "EGGX Landmark Positional Grid Reference") { 51 | grid = screen->GetPlugIn()->SectorFileElementSelectNext(grid, 13); 52 | gridName = string(grid.GetName()); 53 | } 54 | 55 | // Find the grid number freetext 56 | CSectorElement freetext(screen->GetPlugIn()->SectorFileElementSelectFirst(14)); 57 | string freetextName = string(freetext.GetName()); 58 | while (freetextName.find("CZQO Grid Reference Numbers.") == string::npos || freetextName.find("EGGX Grid Reference Numbers.") == string::npos) { 59 | freetext = screen->GetPlugIn()->SectorFileElementSelectNext(freetext, 14); 60 | freetextName = string(freetext.GetName()); 61 | } 62 | 63 | // Show the freetext 64 | string componentName; 65 | while (freetextName.find("CZQO Grid Reference Numbers.") != string::npos || freetextName.find("EGGX Grid Reference Numbers.") != string::npos) { 66 | componentName = freetext.GetComponentName(0); 67 | screen->ShowSectorFileElement(freetext, componentName.c_str(), true); 68 | freetext = screen->GetPlugIn()->SectorFileElementSelectNext(freetext, 14); 69 | freetextName = string(freetext.GetName()); 70 | } 71 | 72 | 73 | } 74 | else { // Not showing it 75 | // Get sector file and element 76 | screen->GetPlugIn()->SelectActiveSectorfile(); 77 | CSectorElement grid(screen->GetPlugIn()->SectorFileElementSelectFirst(13)); 78 | string gridName = string(grid.GetName()); 79 | 80 | // Find the grid 81 | while (gridName != "CZQO Landmark Positional Grid Reference" || gridName != "EGGX Landmark Positional Grid Reference") { 82 | grid = screen->GetPlugIn()->SectorFileElementSelectNext(grid, 13); 83 | gridName = string(grid.GetName()); 84 | } 85 | 86 | // Find the grid number freetext 87 | CSectorElement freetext(screen->GetPlugIn()->SectorFileElementSelectFirst(14)); 88 | string freetextName = string(freetext.GetName()); 89 | while (freetextName.find("CZQO Grid Reference Numbers.") == string::npos || freetextName.find("EGGX Grid Reference Numbers.") == string::npos) { 90 | freetext = screen->GetPlugIn()->SectorFileElementSelectNext(freetext, 14); 91 | freetextName = string(freetext.GetName()); 92 | } 93 | 94 | // Hide the freetext 95 | string componentName; 96 | while (freetextName.find("CZQO Grid Reference Numbers.") != string::npos || freetextName.find("EGGX Grid Reference Numbers.") != string::npos) { 97 | componentName = freetext.GetComponentName(0); 98 | screen->ShowSectorFileElement(freetext, componentName.c_str(), false); 99 | freetext = screen->GetPlugIn()->SectorFileElementSelectNext(freetext, 14); 100 | freetextName = string(freetext.GetName()); 101 | } 102 | 103 | // Hide the grid 104 | screen->ShowSectorFileElement(grid, "", false); 105 | }*/ 106 | 107 | // Refresh the map content 108 | screen->RefreshMapContent(); 109 | screen->RequestRefresh(); 110 | } -------------------------------------------------------------------------------- /VatsimNAAATS/Utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "EuroScopePlugIn.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "Structures.h" 10 | 11 | using namespace std; 12 | using namespace EuroScopePlugIn; 13 | 14 | class CUtils { // TODO: refactor into namespace 15 | public: 16 | // Variables to save 17 | static int InboundX; 18 | static int InboundY; 19 | static int OthersX; 20 | static int OthersY; 21 | static int ConflictX; // save 22 | static int ConflictY; // save 23 | static int RCLX; // save 24 | static int RCLY; // save 25 | static int TrackWindowX; 26 | static int TrackWindowY; 27 | static int AltFiltLow; 28 | static int AltFiltHigh; 29 | static bool GridEnabled; 30 | static bool TagsEnabled; 31 | static bool QckLookEnabled; 32 | static bool OverlayEnabled; 33 | static int AreaSelection; 34 | static int SelectedOverlay; 35 | static int PosType; 36 | static int SepMinimaVertical; 37 | static int SepMinimaLateral; 38 | static int SepMinimaLongitudinal; 39 | 40 | // Load/save methods 41 | static void SavePluginData(CRadarScreen* screen); 42 | static void LoadPluginData(CRadarScreen* screen); 43 | 44 | // Text wrapping 45 | static bool WrapText(CDC* dc, string textToWrap, char wrapChar, int contentWidth, vector* ptrWrappedText); 46 | 47 | // Split string 48 | static bool StringSplit(string str, char splitBy, vector* ptrTokens); 49 | 50 | // Phraseology parser 51 | static string ParseToPhraseology(string rawInput, CMessageType type, string callsign); 52 | 53 | // Raw format parser 54 | static string ParseToRaw(string callsign, CMessageType type, CAircraftFlightPlan* copy = nullptr); 55 | 56 | // Convert coordinates to various type 57 | static string ConvertCoordinateFormat(string coordinateString, int format); 58 | 59 | // Get the aircraft direction 60 | static bool GetAircraftDirection(int heading); 61 | 62 | // Check if point is an entry point (direction: true = Gander, false = Shanwick) 63 | static bool IsEntryPoint(string pointName, bool direction); 64 | 65 | // Check if point is an exit point (direction: true = Gander, false = Shanwick) 66 | static bool IsExitPoint(string pointName, bool direction); 67 | 68 | // Check if the aircraft is to be displayed on the screen 69 | static bool IsAircraftRelevant(CRadarScreen* screen, CRadarTarget* target, bool filtersDisabled = false); 70 | 71 | // Check if aircraft is AGCS equipped 72 | static bool IsAircraftEquipped(string rawRemarks, string rawAcInfo, char equipCode); 73 | 74 | // Get CPosition from lat/lon 75 | static CPosition PositionFromLatLon(double lat, double lon); 76 | 77 | // Calculate Mach 78 | static int GetMach(int groundSpeed, int speedSound); 79 | 80 | // Get radar target mode 81 | static CRadarTargetMode GetTargetMode(int radarFlags); 82 | 83 | // Get radar target mode 84 | static int GetTargetModeInt(int radarFlags); 85 | 86 | // Pad zeroes 87 | static string PadWithZeros(int width, int number); 88 | 89 | // Check all alpha 90 | static bool IsAllAlpha(string str); 91 | 92 | // Find selcal code from remarks 93 | static string GetSelcalCode(CFlightPlan* fpData); 94 | 95 | // Parse zulu time 96 | static string ParseZuluTime(bool delimit, int deltaTime = -1, CFlightPlan* fp = nullptr, int ep = -1); 97 | 98 | // Distance between two points in screen coordinates 99 | static int GetDistanceBetweenPoints(POINT p1, POINT p2); 100 | 101 | // Midpoint 102 | static POINT GetMidPoint(POINT p1, POINT p2); 103 | 104 | // Time (minutes) based on distance and speed 105 | static int GetTimeDistanceSpeed(int distanceNM, int speedGS); 106 | 107 | // Distance (metres) based on speed and time 108 | static double GetDistanceSpeedTime(int speedGS, int timeSec); 109 | 110 | // Metres to nautical miles 111 | static double MetresToNauticalMiles(double metres); 112 | 113 | // Degrees to radians 114 | static double ToRadians(double degrees); 115 | 116 | // Radians to degrees 117 | static double ToDegrees(double radians); 118 | 119 | // Round a double 120 | static string RoundDecimalPlaces(double num, int precision); 121 | 122 | // General solution to get the angle between two intersecting paths 123 | static double GetPathAngle(double hdg1, double hdg2); 124 | 125 | // Get a point based on distance and a heading 126 | static CPosition GetPointDistanceBearing(CPosition position, int distanceMetres, int heading); 127 | 128 | // Get intersection of two vectors 129 | static POINT GetIntersectionFromPointBearing(POINT position1, POINT position2, double bearing1, double bearing2); 130 | 131 | // Get parsed lat lon string (i.e. with N/S or E/W) 132 | static string GetLatLonString(CPosition* pos, bool space = true, int precision = -1, bool showDecimal = true); 133 | 134 | // So we can stop running threads 135 | static HANDLE GetESProcess(); 136 | 137 | // We need this struct for flight plan threading 138 | struct CAsyncData { 139 | CRadarScreen* Screen; 140 | string Callsign; 141 | CAircraftFlightPlan* FP = nullptr; 142 | }; 143 | 144 | // This is for asyncing vNAAATS API data 145 | struct CNetworkAsyncData { 146 | CRadarScreen* Screen; 147 | string Callsign; 148 | CPlugIn* plugin = nullptr; 149 | CNetworkFlightPlan* FP = nullptr; 150 | }; 151 | 152 | // DLL path 153 | static char DllPathFile[_MAX_PATH]; 154 | static string DllPath; 155 | }; -------------------------------------------------------------------------------- /VatsimNAAATS/VatsimNAAATS.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | Source Files 59 | 60 | 61 | Source Files 62 | 63 | 64 | Source Files 65 | 66 | 67 | Source Files 68 | 69 | 70 | Source Files 71 | 72 | 73 | Source Files 74 | 75 | 76 | Source Files 77 | 78 | 79 | Source Files 80 | 81 | 82 | Source Files 83 | 84 | 85 | Source Files 86 | 87 | 88 | Source Files 89 | 90 | 91 | Source Files 92 | 93 | 94 | 95 | 96 | Source Files 97 | 98 | 99 | Resource Files 100 | 101 | 102 | 103 | 104 | Header Files 105 | 106 | 107 | Header Files 108 | 109 | 110 | Header Files 111 | 112 | 113 | Header Files 114 | 115 | 116 | Header Files 117 | 118 | 119 | Header Files 120 | 121 | 122 | Header Files 123 | 124 | 125 | Header Files 126 | 127 | 128 | Header Files 129 | 130 | 131 | Header Files 132 | 133 | 134 | Header Files 135 | 136 | 137 | Header Files 138 | 139 | 140 | Header Files 141 | 142 | 143 | Header Files 144 | 145 | 146 | Header Files 147 | 148 | 149 | Header Files 150 | 151 | 152 | Header Files 153 | 154 | 155 | Header Files 156 | 157 | 158 | Header Files 159 | 160 | 161 | Header Files 162 | 163 | 164 | Header Files 165 | 166 | 167 | Header Files 168 | 169 | 170 | Header Files 171 | 172 | 173 | Header Files 174 | 175 | 176 | Header Files 177 | 178 | 179 | Header Files 180 | 181 | 182 | Header Files 183 | 184 | 185 | Header Files 186 | 187 | 188 | Header Files 189 | 190 | 191 | Header Files 192 | 193 | 194 | Header Files 195 | 196 | 197 | Header Files 198 | 199 | 200 | 201 | 202 | Resource Files 203 | 204 | 205 | -------------------------------------------------------------------------------- /VatsimNAAATS/Constants.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | using namespace EuroScopePlugIn; 11 | 12 | /// WAYPOINTS 13 | // Entry Waypoints 14 | const vector pointsGander = { "AVPUT", 15 | "CLAVY", 16 | "EMBOK", 17 | "KETLA", 18 | "LIBOR", 19 | "MAXAR", 20 | "NIFTY", 21 | "PIDSO", 22 | "RADUN", 23 | "SAVRY", 24 | "TOXIT", 25 | "URTAK", 26 | "VESMI", 27 | "AVUTI", 28 | "BOKTO", 29 | "CUDDY", 30 | "DORYY", 31 | "ENNSO", 32 | "HOIST", 33 | "IRLOK", 34 | "JANJO", 35 | "KODIK", 36 | "LOMSI", 37 | "MELDI", 38 | "NEEKO", 39 | "PELTU", 40 | "RIKAL", 41 | "SAXAN", 42 | "TUDEP", 43 | "UMESI", 44 | "ALLRY", 45 | "BUDAR", 46 | "ELSIR", 47 | "IBERG", 48 | "JOOPY", 49 | "MUSAK", 50 | "NICSO", 51 | "OMSAT", 52 | "PORTI", 53 | "RELIC", 54 | "SUPRY", 55 | "RAFIN", 56 | "JAROM", 57 | "BOBTU" 58 | }; 59 | 60 | const vector pointsShanwick = { "RATSU", 61 | "LUSEN", 62 | "ATSIX", 63 | "ORTAV", 64 | "BALIX", 65 | "ADODO", 66 | "ERAKA", 67 | "ETILO", 68 | "GOMUP", 69 | "AGORI", 70 | "SUNOT", 71 | "BILTO", 72 | "PIKIL", 73 | "ETARI", 74 | "RESNO", 75 | "VENER", 76 | "DOGAL", 77 | "NEBIN", 78 | "MALOT", 79 | "TOBOR", 80 | "LIMRI", 81 | "ADARA", 82 | "DINIM", 83 | "RODEL", 84 | "SOMAX", 85 | "KOGAD", 86 | "BEDRA", 87 | "NERTU", 88 | "NASBA", 89 | "OMOKO", 90 | "TAMEL", 91 | "GELPO", 92 | "LASNO", 93 | "ETIKI", 94 | "UMLER", 95 | "SEPAL", 96 | "BUNAV", 97 | "SIVIR", 98 | "BEGAS", 99 | "DIVAT", 100 | "DIXIS", 101 | "BERUX", 102 | "PITAX", 103 | "PASAS", 104 | "NILAV", 105 | "GONAN", 106 | "ATSUR" 107 | }; 108 | 109 | /// VALUES 110 | // Plugin info 111 | const string PLUGIN_NAME = "vNAAATS"; 112 | const string PLUGIN_VERSION = "1.3b2"; 113 | const string PLUGIN_AUTHOR = "Andrew Ogden github.com/andrewogden1678"; 114 | const string PLUGIN_COPYRIGHT = "(C) 2021 Andrew Ogden vNAAATS"; 115 | const bool IS_ALPHA = true; 116 | const bool DEBUG_MODE = true; 117 | 118 | // Sector file & geo constants 119 | const int SECTELEMENT_COORD_IDX = 7; 120 | const int RADIUS_EARTH_NM = 3440; 121 | 122 | // Screen details 123 | #define DISPLAY_NAME "vNAAATS Display" 124 | 125 | // Text, margins and padding 126 | const int MEN_FONT_SIZE = 16; 127 | const int BTN_PAD_SIDE = 4; 128 | const int BTN_PAD_TOP = 6; 129 | 130 | // Lists 131 | const int LIST_INBOUND_WIDTH = 400; 132 | const int LIST_OTHERS_WIDTH = 110; 133 | const int LIST_RCLS_WIDTH = 110; 134 | const int LIST_CONFLICT_WIDTH = 150; 135 | 136 | // Menu bar 137 | const int MENBAR_HEIGHT = 100; 138 | const int MENBAR_BTN_HEIGHT = 30; 139 | const int RECT1_WIDTH = 500; 140 | const int RECT2_WIDTH = 340; 141 | const int RECT3_WIDTH = 160; 142 | const int RECT4_WIDTH = 100; 143 | const int RECT5_WIDTH = 250; 144 | const int RECT6_WIDTH = 100; 145 | const int RECT7_WIDTH = 180; 146 | const int RECT8_WIDTH = 190; 147 | 148 | // Window sizes 149 | const int WINSZ_TITLEBAR_HEIGHT = 20; 150 | const int WINSZ_TCKINFO_WIDTH = 600; 151 | const int WINSZ_TCKINFO_HEIGHT = 300; 152 | const int WINSZ_FLTPLN_WIDTH = 540; 153 | const int WINSZ_FLTPLN_HEIGHT_INIT = 175; 154 | const int WINSZ_FLTPLN_HEIGHT_DATA = 190; 155 | const int WINSZ_FLTPLN_HEIGHT_MANETRY = 175; 156 | const int WINSZ_FLTPLN_HEIGHT_CPY = 190; 157 | const int WINSZ_FLTPLN_HEIGHT_MSG = 175; 158 | const int WINSZ_FLTPLN_HEIGHT_XTRA = 165; 159 | const int WINSZ_FLTPLN_WIDTH_MDL = 375; 160 | const int WINSZ_FLTPLN_WIDTH_COORD = 350; 161 | const int WINSZ_FLTPLN_HEIGHT_COORD = 280; 162 | const int WINSZ_FLTPLN_HEIGHT_ATCR = 260; 163 | const int WINSZ_FLTPLN_HEIGHT_HIST = 250; 164 | const int WINSZ_FLTPLN_WIDTH_HIST = 500; 165 | const int WINSZ_FLTPLN_HEIGHT_TSFR = 260; 166 | const int WINSZ_MSG_WIDTH = 550; 167 | const int WINSZ_MSG_HEIGHT = 315; 168 | const int WINSZ_NP_WIDTH = 250; 169 | const int WINSZ_NP_HEIGHT = 300; 170 | 171 | // Conflict 172 | const int SEPTOOL_TIME = 2700; // 45 minutes 173 | const int STCA_TIME = 480; // 8 minutes 174 | 175 | /// OBJECT HANDLES 176 | // Screen 177 | const int RADAR_SCREEN = -1; 178 | const int SCREEN_TAG = 1; 179 | const int SCREEN_TAG_CS = 11; 180 | const int SCREEN_TAG_CS_BTN = 12; 181 | const int MENBAR = 2; 182 | const int WINDOW = 3; 183 | 184 | // Window object handles (for buttons, etc) 185 | const int WIN_TCKINFO = 101; 186 | const int WIN_FLTPLN = 102; 187 | const int WIN_SCROLLBAR = 103; 188 | const int WIN_MSG = 104; 189 | const int WIN_NOTEPAD = 105; 190 | const int WIN_FLTPLN_TSFR = 106; 191 | 192 | // Text inputs and functions 193 | const int ALTFILT_TEXT = 200; 194 | const int FUNC_ALTFILT_LOW = 201; 195 | const int FUNC_ALTFILT_HIGH = 202; 196 | const int ACTV_MESSAGE = 203; 197 | 198 | // Lists 199 | const int LIST_INBOUND = 300; 200 | const int LIST_OTHERS = 301; 201 | const int LIST_RCLS = 302; 202 | const int LIST_CONFLICT = 303; 203 | 204 | // Dropdown 205 | const int DRP_AREA_EGGX = 801; 206 | const int DRP_AREA_CZQX = 802; 207 | const int DRP_AREA_BDBX = 803; 208 | const int DRP_OVL_ALL = 800; 209 | const int DRP_OVL_EAST = 801; 210 | const int DRP_OVL_WEST = 802; 211 | const int DRP_OVL_SEL = 803; 212 | const int DRP_TYPE_DEL = 801; 213 | const int DRP_TYPE_ENR = 802; 214 | const int DRP_TYPE_MULTI = 803; 215 | 216 | /// SETTINGS VARIABLES 217 | const string SET_INBNDX = "InboundX"; 218 | const string SET_INBNDY = "InboundY"; 219 | const string SET_OTHERSX = "OthersX"; 220 | const string SET_OTHERSY = "OthersY"; 221 | const string SET_ALTFILT_LOW = "AltFiltLow"; 222 | const string SET_ALTFILT_HIGH = "AltFiltHigh"; 223 | const string SET_GRID = "GridEnabled"; 224 | const string SET_TAGS = "TagsEnabled"; 225 | const string SET_QCKLOOK = "QckLookEnabled"; 226 | const string SET_OVERLAY = "OverlayEnabled"; 227 | const string SET_AREASEL = "SelectedArea"; 228 | const string SET_OVERLAYSEL = "SelectedOverlay"; 229 | const string SET_POSTYPESEL = "SelectedPosType"; 230 | 231 | /// ENUMS 232 | // Path type enum 233 | enum class CPathType { 234 | RTE, 235 | PIV, 236 | TCKS 237 | }; 238 | 239 | // Track direction enum 240 | enum class CTrackDirection { 241 | UNKNOWN, 242 | WEST, 243 | EAST 244 | }; 245 | 246 | // Type of overlay 247 | enum class COverlayType { 248 | TCKS_ALL, 249 | TCKS_EAST, 250 | TCKS_WEST, 251 | TCKS_ACTV, 252 | TCKS_SEL 253 | }; 254 | 255 | // Conflict status 256 | enum class CConflictStatus { 257 | OK, 258 | WARNING, 259 | CRITICAL 260 | }; 261 | 262 | // Longitudinal trackstatus 263 | enum class CTrackStatus { 264 | NA, 265 | CROSSING, 266 | RECIPROCAL, 267 | OPPOSITE, 268 | SAME 269 | }; 270 | 271 | // Button states 272 | enum class CInputState { 273 | INACTIVE, 274 | ACTIVE, 275 | DISABLED 276 | }; 277 | 278 | // Flight plan mode 279 | enum class CFlightPlanMode { 280 | NOT_OWNED, 281 | INIT, 282 | DATA, 283 | DATA_COPY, 284 | CLEARANCE, 285 | PROBE 286 | }; 287 | 288 | enum class CMessageType { 289 | LOG_ON, 290 | LOG_ON_CONFIRM, 291 | LOG_ON_REJECT, 292 | TRANSFER, 293 | TRANSFER_ACCEPT, 294 | TRANSFER_REJECT, 295 | CLEARANCE_REQ, 296 | CLEARANCE_ISSUE, 297 | CLEARANCE_REJECT, 298 | REVISION_REQ, 299 | REVISION_ISSUE, 300 | REVISION_REJECT, 301 | WILCO, 302 | ROGER, 303 | UNABLE 304 | }; 305 | 306 | enum class CRestrictionType { 307 | LCHG, 308 | MCHG, 309 | EPC, 310 | RERUTE, 311 | UNABLE, 312 | RTD, 313 | ATA, 314 | ATB, 315 | XAT, 316 | INT 317 | }; 318 | 319 | enum class CRadarTargetMode { 320 | PRIMARY, // Asterisk (0) 321 | SECONDARY_S, // Diamond with line (1) 322 | SECONDARY_C, // Star (2) 323 | ADS_B, // Airplane icon (also for cleared aircraft) (3) 324 | }; 325 | 326 | enum class CLogType { 327 | INIT, // Initialisation message 328 | NORM, // General log item 329 | WARN, // Warning 330 | ERR, // Handled exception 331 | EXC, // Unhandled exception 332 | }; -------------------------------------------------------------------------------- /VatsimNAAATS/FlightPlanWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "EuroScopePlugIn.h" 4 | #include "ConflictDetection.h" 5 | #include 6 | #include 7 | #include 8 | #include "BaseWindow.h" 9 | 10 | using namespace std; 11 | using namespace Gdiplus; 12 | using namespace EuroScopePlugIn; 13 | 14 | class CFlightPlanWindow : public CBaseWindow 15 | { 16 | private: 17 | CAircraftFlightPlan copiedPlan; 18 | map subWindowPositions; 19 | map restrictionSelections; 20 | map> currentProbeStatuses; 21 | int selectedRestriction = -1; 22 | int selectedActiveRestriction = -1; 23 | string currentClearanceText; 24 | clock_t fiveSecondTimer = clock(); 25 | 26 | public: 27 | CAircraftFlightPlan* primedPlan = nullptr; 28 | unordered_map onlineControllers; 29 | string selectedAuthority = ""; 30 | // Inherited methods 31 | CFlightPlanWindow(POINT topLeft); 32 | virtual void MakeWindowItems(); 33 | virtual void RenderWindow(CDC* dc, Graphics* g, CRadarScreen* screen); 34 | CRect RenderDataPanel(CDC* dc, Graphics* g, CRadarScreen* screen, POINT topLeft, bool isCopy); 35 | void RenderConflictWindow(CDC* dc, Graphics* g, CRadarScreen* screen, POINT topLeft); 36 | void RenderMessageWindow(CDC* dc, Graphics* g, CRadarScreen* screen, POINT bottomLeft); 37 | void RenderClearanceWindow(CDC* dc, Graphics* g, CRadarScreen* screen, POINT topLeft); 38 | void RenderManEntryWindow(CDC* dc, Graphics* g, CRadarScreen* screen, POINT topLeft); 39 | void RenderCoordModal(CDC* dc, Graphics* g, CRadarScreen* screen, POINT topLeft); 40 | void RenderHistoryModal(CDC* dc, Graphics* g, CRadarScreen* screen, POINT topLeft); 41 | void RenderATCRestrictModal(CDC* dc, Graphics* g, CRadarScreen* screen, POINT topLeft); 42 | void RenderExchangeModal(CDC* dc, Graphics* g, CRadarScreen* screen, POINT topLeft); 43 | void RenderATCRestrictSubModal(CDC* dc, Graphics* g, CRadarScreen* screen, POINT topLeft); 44 | void MoveSubWindow(int id, POINT topLeft); 45 | 46 | // Button clicks 47 | virtual void ButtonDown(int id); 48 | virtual void ButtonUp(int id, CRadarScreen* screen = nullptr); 49 | virtual void ButtonPress(int id); 50 | virtual void ButtonUnpress(int id); 51 | virtual void ButtonDoubleClick(int id); 52 | virtual void SetButtonState(int id, CInputState state); 53 | void SetTextValue(CRadarScreen* screen, int id, string content); 54 | CInputState GetInputState(int id); 55 | bool IsButtonPressed(int id); 56 | 57 | // Fill data 58 | void Instantiate(CRadarScreen* screen, string callsign, CMessage* msg = nullptr); 59 | void ParseRestriction(string content, CRestrictionType type); 60 | 61 | // Panel states 62 | bool IsData = false; 63 | bool IsCopyMade = false; 64 | bool IsConflictWindow = false; 65 | bool IsClearanceOpen = false; 66 | bool IsManualEntryOpen = false; 67 | bool IsMessageOpen = false; 68 | bool IsCoordOpen = false; 69 | bool IsHistoryOpen = false; 70 | bool IsATCRestrictionsOpen = false; 71 | bool IsTransferOpen = false; 72 | int RestrictionSubModalType = -1; 73 | 74 | // Subwindow definitions 75 | static const int SUBWIN_ATCR = 400; 76 | static const int SUBWIN_COORD = 401; 77 | static const int SUBWIN_HIST = 402; 78 | static const int SUBWIN_XCHANGE = 403; 79 | 80 | // Button definitions 81 | static const int BTN_CLOSE = 0; 82 | static const int BTN_COPY = 1; 83 | static const int BTN_UNCLEAR = 2; 84 | static const int BTN_COORD = 3; 85 | static const int BTN_MANENTRY = 4; 86 | static const int BTN_PROBE = 5; 87 | static const int BTN_DELETE = 6; 88 | static const int BTN_ADS = 7; 89 | static const int BTN_READBK = 8; 90 | static const int BTN_MSG = 9; 91 | static const int BTN_HIST = 10; 92 | static const int BTN_SAVE = 11; 93 | static const int BTN_ATCR = 12; 94 | static const int BTN_ATCR_CPY = 13; 95 | static const int BTN_MSG_REMOVE = 14; 96 | static const int BTN_MSG_DONE = 15; 97 | static const int BTN_MSG_CLOSE = 16; 98 | static const int BTN_MSG_REQUEUE = 17; 99 | static const int BTN_MSG_FORWARD = 18; 100 | static const int BTN_CONF_ACCCL = 19; 101 | static const int BTN_CONF_MANCL = 20; 102 | static const int BTN_CONF_COORD = 21; 103 | static const int BTN_CONF_CLOSE = 22; 104 | static const int BTN_MAN_CANCEL = 23; 105 | static const int BTN_MAN_SUBMIT = 24; 106 | static const int BTN_CLRC_READBK = 25; 107 | static const int BTN_CLRC_SEND = 26; 108 | static const int BTN_CLRC_VOICE = 27; 109 | static const int BTN_CLRC_REJECT = 28; 110 | static const int BTN_ATCR_ADD = 29; 111 | static const int BTN_ATCR_CANCEL = 30; 112 | static const int BTN_ATCR_OK = 31; 113 | static const int BTN_XCHANGE_NOTIFY = 32; 114 | static const int BTN_XCHANGE_CLOSE = 33; 115 | static const int BTN_XCHANGE_ACCEPT = 34; 116 | static const int BTN_XCHANGE_TRANSFER = 35; 117 | static const int BTN_XCHANGE_REJECT = 36; 118 | static const int BTN_XCHANGE_TRACK = 37; 119 | static const int BTN_COORD_CLOSE = 38; 120 | static const int BTN_COORD_SENDOK = 39; 121 | static const int BTN_HIST_CLOSE = 40; 122 | static const int BTN_RESTRI_EDIT_CLOSE = 41; 123 | static const int BTN_RESTRI_EDIT_OK = 42; 124 | 125 | // Dropdown definitions 126 | static const int DRP_ATCR = 200; 127 | static const int DRP_ATCR_CPY = 201; 128 | 129 | // Text definitions 130 | static const int TXT_ACID = 100; 131 | static const int TXT_TYPE = 101; 132 | static const int TXT_DEPART = 102; 133 | static const int TXT_ETD = 103; 134 | static const int TXT_SELCAL = 104; 135 | static const int TXT_DATALINK = 105; 136 | static const int TXT_COMMS = 106; 137 | static const int TXT_OWNERSHIP = 107; 138 | static const int TXT_SPD = 108; 139 | static const int TXT_LEVEL = 109; 140 | static const int TXT_DEST = 110; 141 | static const int TXT_TCK = 111; 142 | static const int TXT_STATE = 112; 143 | static const int TXT_SPD_CPY = 113; 144 | static const int TXT_LEVEL_CPY = 114; 145 | static const int TXT_DEST_CPY = 115; 146 | static const int TXT_TCK_CPY = 116; 147 | static const int TXT_STATE_CPY = 117; 148 | static const int TXT_MAN_FL = 118; 149 | static const int TXT_MAN_SPD = 119; 150 | static const int TXT_MAN_TCK = 120; 151 | static const int TXT_MAN_DEST = 121; 152 | static const int TXT_MAN_EP = 122; 153 | static const int TXT_MAN_EPTIME = 123; 154 | static const int TXT_XCHANGE_CURRENT = 124; 155 | static const int TXT_XCHANGE_NEXT = 125; 156 | static const int TXT_MAN_RTE = 126; 157 | static const int TXT_RTE = 127; 158 | static const int TXT_CPY_RTE = 128; 159 | static const int TXT_RESTRI_LCHG_LATLON = 129; 160 | static const int TXT_RESTRI_LCHG_TIME = 130; 161 | static const int TXT_RESTRI_MCHG_LATLON = 131; 162 | static const int TXT_RESTRI_MCHG_TIME = 132; 163 | static const int TXT_RESTRI_ATA_LATLON = 133; 164 | static const int TXT_RESTRI_ATA_TIME = 134; 165 | static const int TXT_RESTRI_ATB_LATLON = 135; 166 | static const int TXT_RESTRI_ATB_TIME = 136; 167 | static const int TXT_RESTRI_XAT_LATLON = 137; 168 | static const int TXT_RESTRI_XAT_TIME = 138; 169 | static const int TXT_RESTRI_INT_CALLSIGN = 139; 170 | static const int TXT_RESTRI_INT_INTERVAL = 140; 171 | static const int TXT_EQUIPPED = 141; 172 | static const int TXT_CPY_EQUIPPED = 142; 173 | 174 | // Checkbox definitions 175 | static const int CHK_CLRC_ORCA = 300; 176 | static const int CHK_CLRC_VOX = 301; 177 | static const int CHK_CLRC_CPDLC = 302; 178 | static const int CHK_CLRC_TXT = 303; 179 | static const int CHK_COORD_CZQOV = 304; 180 | static const int CHK_COORD_EGGXV = 305; 181 | static const int CHK_COORD_BIRDV = 306; 182 | static const int CHK_COORD_ZNYV = 307; 183 | static const int CHK_COORD_LPPOV = 308; 184 | static const int CHK_COORD_EISNV = 309; 185 | static const int CHK_COORD_CZQXV = 310; 186 | static const int CHK_COORD_CZULV = 311; 187 | static const int CHK_COORD_EGPXV = 312; 188 | static const int CHK_COORD_LFRRV = 313; 189 | static const int CHK_COORD_PLANV = 314; 190 | static const int CHK_COORD_ENRV = 315; 191 | 192 | static const int CHK_COORD_CZQOT = 360; // We start here from 360 because we need to be able to know that this is manual 193 | static const int CHK_COORD_EGGXT = 361; 194 | static const int CHK_COORD_BIRDT = 362; 195 | static const int CHK_COORD_ZNYT = 363; 196 | static const int CHK_COORD_LPPOT = 364; 197 | static const int CHK_COORD_EISNT = 365; 198 | static const int CHK_COORD_CZQXT = 366; 199 | static const int CHK_COORD_CZULT = 367; 200 | static const int CHK_COORD_EGPXT = 368; 201 | static const int CHK_COORD_LFRRT = 369; 202 | static const int CHK_COORD_PLANT = 370; 203 | static const int CHK_COORD_ENRT = 371; 204 | static const int CHK_RESTRI_LCHG = 372; 205 | static const int CHK_RESTRI_MCHG = 373; 206 | static const int CHK_RESTRI_UNABLE_SPD = 374; 207 | static const int CHK_RESTRI_UNABLE_LVL = 375; 208 | static const int CHK_RESTRI_UNABLE_RTE = 376; 209 | 210 | // Selection definitions 211 | static const int SEL_ATCR_LCHG = 400; 212 | static const int SEL_ATCR_MCHG = 401; 213 | static const int SEL_ATCR_EPC = 402; 214 | static const int SEL_ATCR_RERUTE = 403; 215 | static const int SEL_ATCR_RTD = 404; 216 | static const int SEL_ATCR_UNABLE = 405; 217 | static const int SEL_ATCR_ATA = 406; 218 | static const int SEL_ATCR_ATB = 407; 219 | static const int SEL_ATCR_XAT = 408; 220 | static const int SEL_ATCR_INT = 409; 221 | 222 | // Scroll bar definitions 223 | static const int SCRL_DATA = 500; 224 | static const int SCRL_CPY = 501; 225 | static const int SCRL_CONF_X = 502; 226 | static const int SCRL_CONF_Y = 503; 227 | static const int SCRL_HIST = 504; 228 | static const int SCRL_MSG = 505; 229 | static const int SCRL_CLRC = 506; 230 | static const int SCRL_CLRC_XTRA = 507; 231 | static const int SCRL_MANENTRY = 508; 232 | static const int SCRL_COORD_STATIONS = 509; 233 | static const int SCRL_COORD_HIST = 510; 234 | static const int SCRL_XCHANGE = 511; 235 | }; 236 | 237 | -------------------------------------------------------------------------------- /VatsimNAAATS/TrackInfoWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "TrackInfoWindow.h" 3 | #include "Styles.h" 4 | #include "RoutesHelper.h" 5 | #include "DataHandler.h" 6 | 7 | using namespace Colours; 8 | 9 | const int CTrackInfoWindow::BTN_CLOSE = 0; 10 | const int CTrackInfoWindow::BTN_REFRESH = 1; 11 | 12 | CTrackInfoWindow::CTrackInfoWindow(POINT topLeft) : CBaseWindow(topLeft) { 13 | // Make buttons 14 | MakeWindowItems(); 15 | 16 | // Close by default 17 | IsClosed = true; 18 | }; 19 | 20 | void CTrackInfoWindow::MakeWindowItems() { 21 | windowButtons[BTN_REFRESH] = CWinButton(BTN_REFRESH, WIN_TCKINFO, "Refresh Tck Data", CInputState::INACTIVE); 22 | windowButtons[BTN_CLOSE] = CWinButton(BTN_CLOSE, WIN_TCKINFO, "Close", CInputState::INACTIVE); 23 | } 24 | 25 | void CTrackInfoWindow::RenderWindow(CDC* dc, Graphics* g, CRadarScreen* screen, CMenuBar* menuBar) { 26 | // Save device context 27 | int iDC = dc->SaveDC(); 28 | 29 | // Create brushes 30 | CBrush darkerBrush(ScreenBlue.ToCOLORREF()); 31 | CBrush lighterBrush(WindowBorder.ToCOLORREF()); 32 | CBrush evenDarkerBrush(ButtonPressed.ToCOLORREF()); 33 | 34 | // Select title font 35 | FontSelector::SelectNormalFont(16, dc); 36 | dc->SetTextColor(Black.ToCOLORREF()); 37 | dc->SetTextAlign(TA_CENTER); 38 | 39 | // Create base window rectangle 40 | CRect windowRect(topLeft.x, topLeft.y, topLeft.x + WINSZ_TCKINFO_WIDTH, topLeft.y + WINSZ_TCKINFO_HEIGHT); 41 | dc->FillRect(windowRect, &darkerBrush); 42 | 43 | // Create titlebar 44 | CRect titleRect(windowRect.left, windowRect.top, windowRect.left + WINSZ_TCKINFO_WIDTH, windowRect.top + WINSZ_TITLEBAR_HEIGHT); 45 | dc->FillRect(titleRect, &lighterBrush); 46 | dc->DrawEdge(titleRect, EDGE_RAISED, BF_BOTTOM); 47 | dc->TextOutA(titleRect.left + (WINSZ_TCKINFO_WIDTH / 2), titleRect.top + (WINSZ_TITLEBAR_HEIGHT / 7), string("Track Info - TMI: " + CRoutesHelper::CurrentTMI).c_str()); 48 | 49 | // Create button bar 50 | CRect buttonBarRect(windowRect.left, windowRect.bottom - 50, windowRect.left + WINSZ_TCKINFO_WIDTH, windowRect.bottom); 51 | dc->FillRect(buttonBarRect, &darkerBrush); 52 | dc->Draw3dRect(buttonBarRect, BevelLight.ToCOLORREF(), ScreenBlue.ToCOLORREF()); 53 | InflateRect(buttonBarRect, -1, -1); 54 | dc->Draw3dRect(buttonBarRect, BevelLight.ToCOLORREF(), ScreenBlue.ToCOLORREF()); 55 | 56 | // Add screen objects 57 | screen->AddScreenObject(WINDOW, "WIN_TCKINFO", windowRect, true, ""); // So that we can't click anything under the flight plan window 58 | screen->AddScreenObject(WINDOW, "TCKINFO", titleRect, true, ""); // Movable 59 | 60 | /// Draw buttons 61 | // Refresh button 62 | CCommonRenders::RenderButton(dc, screen, { buttonBarRect.left + 10, buttonBarRect.top + 10 }, 140, 30, &windowButtons.at(BTN_REFRESH)); 63 | // Close button 64 | CCommonRenders::RenderButton(dc, screen, { (buttonBarRect.right - 60) - 10, buttonBarRect.top + 10 }, 55, 30, &windowButtons.at(BTN_CLOSE)); 65 | 66 | // Draw lines 67 | FontSelector::SelectNormalFont(16, dc); 68 | dc->SetTextColor(TextWhite.ToCOLORREF()); 69 | dc->SetTextAlign(TA_CENTER); 70 | 71 | // Refresh NAT data if clicked 72 | if (NATDataRefresh) { 73 | int status = CDataHandler::PopulateLatestTrackData(screen->GetPlugIn()); 74 | // Set tracks in menu bar 75 | menuBar->MakeDropDownItems(CMenuBar::DRP_TCKCTRL); 76 | // Show data 77 | if (status == 0) { 78 | MsgDataRefresh = "Refresh successful."; 79 | } 80 | else { 81 | MsgDataRefresh = "Failed to refresh."; 82 | } 83 | NATDataRefresh = false; 84 | } 85 | 86 | // Show refresh message 87 | dc->TextOutA(((windowRect.right + windowRect.left) / 2) + 10, buttonBarRect.top + 16, MsgDataRefresh.c_str()); 88 | 89 | // Get a rectangle for the content 90 | int contentSize = CRoutesHelper::CurrentTracks.size() * 45; // We minus 25 because 25 extra is always added on at the end of the loop 91 | CRect scrollContent(windowRect.left, windowRect.top + WINSZ_TITLEBAR_HEIGHT, windowRect.right, windowRect.top + WINSZ_TITLEBAR_HEIGHT + contentSize); 92 | /// Scroll bar mechanics 93 | scrollWindowSize = WINSZ_TCKINFO_HEIGHT - (buttonBarRect.Height() + 3) - (titleRect.Height() + 1); // Size of the window (which is also the size of the track for the scroll grip) 94 | double contentRatio = (double)scrollWindowSize / (double)contentSize; // Ratio of content to window 95 | gripSize = scrollWindowSize * contentRatio; // Based on the ratio, we get the size of the grip 96 | int minGripSize = 20; // Minimum size in case the window is big 97 | // Check that the grip size is not greater than the window size (content is smaller) 98 | if (gripSize > scrollWindowSize) gripSize = scrollWindowSize; // Set the grip size to the window size if it is 99 | if (gripSize < minGripSize) gripSize = minGripSize; // Make sure the minimum grip size is there 100 | // Grip position mechanics 101 | int winScrollAreaSize = contentSize - scrollWindowSize; // Total scrollable area 102 | double windowPosRatio = (double)scrollWindowSize / (double)winScrollAreaSize; // Ratio of window to scrollable area 103 | trackScrollAreaSize = scrollWindowSize - gripSize; // Same as window, do to keep grip flying off end of track 104 | double gripPosOnTrack = trackScrollAreaSize * windowPosRatio + gripPosDelta - ((gripSize != scrollWindowSize) ? gripSize : 0); // This is the location of the grip on the track 105 | 106 | // Now we draw the scroll track 107 | CRect scrollBarTrack(windowRect.right - 13, windowRect.top + titleRect.Height(), windowRect.right, windowRect.bottom - (buttonBarRect.Height() + 2)); 108 | dc->FillRect(scrollBarTrack, &evenDarkerBrush); 109 | dc->Draw3dRect(scrollBarTrack, BevelDark.ToCOLORREF(), BevelLight.ToCOLORREF()); 110 | InflateRect(scrollBarTrack, -1, -1); 111 | dc->Draw3dRect(scrollBarTrack, BevelDark.ToCOLORREF(), BevelLight.ToCOLORREF()); 112 | 113 | // And then the actual scroll grip 114 | CRect scrollGrip(scrollBarTrack.left, scrollBarTrack.top + gripPosOnTrack, scrollBarTrack.right, scrollBarTrack.top + gripPosOnTrack + gripSize); 115 | dc->FillRect(scrollGrip, &darkerBrush); 116 | dc->Draw3dRect(scrollGrip, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 117 | InflateRect(scrollGrip, -1, -1); 118 | dc->Draw3dRect(scrollGrip, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 119 | 120 | // Add the screen object 121 | screen->AddScreenObject(WIN_SCROLLBAR, "TCKINFO", scrollGrip, true, ""); 122 | 123 | // Now we need to get the clipped scroll area 124 | double gripPositionRatio = gripPosOnTrack != 0.0 ? (gripPosOnTrack + gripSize) / trackScrollAreaSize : 0; 125 | double windowPosition = gripPosOnTrack != 0.0 ? gripPositionRatio * winScrollAreaSize - scrollWindowSize : 0; 126 | CRect clipContent(windowRect.left, windowRect.top + WINSZ_TITLEBAR_HEIGHT + windowPosition, windowRect.right, windowRect.top + WINSZ_TITLEBAR_HEIGHT + scrollWindowSize + windowPosition); 127 | // Set offsets for line drawing and spacer size 128 | int offsetX = 25; 129 | int offsetY = 25; 130 | int contentOffsetY = 25; 131 | string spacer = "SPACER"; // To use GetTextExtent() for a consistent sized spacer 132 | // Draw lines 133 | for (auto kv : CRoutesHelper::CurrentTracks) { 134 | int content = (int)scrollContent.top + contentOffsetY; 135 | if (windowRect.top + contentOffsetY >= clipContent.top && windowRect.top + contentOffsetY <= clipContent.bottom) { 136 | dc->TextOutA(windowRect.left + offsetX, windowRect.top + offsetY, "TCK"); 137 | offsetX += dc->GetTextExtent("TCK").cx + 37; 138 | // Output route 139 | for (int i = 0; i < kv.second.Route.size(); i++) { 140 | dc->TextOutA(windowRect.left + offsetX, windowRect.top + offsetY, kv.second.Route[i].c_str()); 141 | offsetX += (int)dc->GetTextExtent(spacer.c_str()).cx; 142 | } 143 | // Reset offsets 144 | offsetX = 24; 145 | offsetY += 20; 146 | } 147 | contentOffsetY += 20; 148 | if (windowRect.top + contentOffsetY >= clipContent.top && windowRect.top + contentOffsetY <= clipContent.bottom) { 149 | // Output track ID 150 | dc->TextOutA(windowRect.left + offsetX, windowRect.top + offsetY, kv.first.c_str()); 151 | offsetX += dc->GetTextExtent(kv.first.c_str()).cx + 43; 152 | // Output flight levels 153 | for (int i = 0; i < kv.second.FlightLevels.size(); i++) { 154 | dc->TextOutA(windowRect.left + offsetX, windowRect.top + offsetY, to_string(kv.second.FlightLevels[i] / 100).c_str()); 155 | offsetX += dc->GetTextExtent(to_string(kv.second.FlightLevels[i] / 100).c_str()).cx + 5; 156 | } 157 | // Reset x offset and increment y offset 158 | offsetX = 25; 159 | offsetY += 25; 160 | } 161 | contentOffsetY += 25; 162 | } 163 | 164 | // Create borders 165 | dc->DrawEdge(windowRect, EDGE_SUNKEN, BF_RECT); 166 | InflateRect(windowRect, 1, 1); 167 | dc->Draw3dRect(windowRect, WindowBorder.ToCOLORREF(), WindowBorder.ToCOLORREF()); 168 | InflateRect(windowRect, 1, 1); 169 | dc->DrawEdge(windowRect, EDGE_RAISED, BF_RECT); 170 | 171 | // Cleanup 172 | DeleteObject(darkerBrush); 173 | DeleteObject(lighterBrush); 174 | 175 | // Restore device context 176 | dc->RestoreDC(iDC); 177 | } 178 | 179 | void CTrackInfoWindow::ButtonUp(int id, CRadarScreen* screen) { 180 | if (id == CTrackInfoWindow::BTN_CLOSE) { // Close button 181 | // Reset window state 182 | MsgDataRefresh = ""; 183 | // Close window 184 | IsClosed = true; 185 | } 186 | if (id == CTrackInfoWindow::BTN_REFRESH) { // Refresh button 187 | // Set data to refreshed so that text comes up 188 | NATDataRefresh = true; 189 | } 190 | // Finally unpress the button 191 | windowButtons.find(id)->second.State = CInputState::INACTIVE; 192 | } 193 | 194 | void CTrackInfoWindow::ButtonDown(int id) { 195 | windowButtons.find(id)->second.State = CInputState::ACTIVE; 196 | } 197 | 198 | void CTrackInfoWindow::ButtonPress(int id) { 199 | 200 | } 201 | 202 | void CTrackInfoWindow::ButtonUnpress(int id) { 203 | 204 | } 205 | 206 | void CTrackInfoWindow::SetButtonState(int id, CInputState state) { 207 | 208 | } 209 | 210 | void CTrackInfoWindow::Scroll(CRect area, POINT mousePtr) { 211 | // Current bar position 212 | if (currentScrollPos.left == 0) { // If initial then just set to the area 213 | currentScrollPos = area; 214 | } 215 | else { 216 | // Get the delta and check whether it is in the bounds, if it is then change position 217 | int delta = gripPosDelta + area.top - currentScrollPos.top; 218 | if (delta > scrollWindowSize - gripSize) { 219 | gripPosDelta = trackScrollAreaSize; 220 | } 221 | else if (delta < 0) { 222 | gripPosDelta = 0; 223 | } 224 | else { 225 | gripPosDelta += area.top - currentScrollPos.top; 226 | } 227 | currentScrollPos = area; 228 | } 229 | } -------------------------------------------------------------------------------- /VatsimNAAATS/Structures.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "Constants.h" 6 | #include 7 | #include 8 | 9 | // Describes a NAT track 10 | struct CTrack { 11 | string Identifier; 12 | string TMI; 13 | vector Route; 14 | vector RouteRaw; 15 | vector FlightLevels; 16 | CTrackDirection Direction; 17 | string validTo; 18 | string validFrom; 19 | }; 20 | 21 | // Describes a point along an aircraft's route 22 | struct CRoutePosition { 23 | string Fix; 24 | CPosition PositionRaw; 25 | string Estimate; 26 | int DistanceFromLastPoint; 27 | int FlightLevel; 28 | }; 29 | 30 | // Describes a generic waypoint 31 | struct CWaypoint { 32 | CWaypoint() {}; // Default constructor 33 | CWaypoint(string name, double lat, double lon) { 34 | Name = name; 35 | Position.m_Latitude = lat; 36 | Position.m_Longitude = lon; 37 | } 38 | string Name; 39 | CPosition Position; 40 | }; 41 | 42 | // Describes an inbound aircraft 43 | struct CInboundAircraft { 44 | CInboundAircraft(string cs, int fA, int cL, string pt, string est, string dest, bool direction) { 45 | Callsign = cs; 46 | FinalAltitude = fA; 47 | ClearedLevel = cL; 48 | Point = pt; 49 | Estimate = est; 50 | Destination = dest; 51 | Direction = direction; 52 | } 53 | string Callsign; 54 | int FinalAltitude; 55 | int ClearedLevel; 56 | string Point; 57 | string Estimate; 58 | string Destination; 59 | bool Direction; 60 | }; 61 | 62 | // Describes a aircraft status 63 | struct CAircraftStatus { 64 | CAircraftStatus() {}; // Default constructor 65 | CAircraftStatus(string cs, int alt, int gs, int hdg, CPosition pos) { 66 | Callsign = cs; 67 | Altitude = alt; 68 | GroundSpeed = gs; 69 | Heading = hdg; 70 | Position = pos; 71 | } 72 | string Callsign; 73 | int Altitude; 74 | int GroundSpeed; 75 | int Heading; 76 | int Estimate; 77 | CPosition Position; 78 | }; 79 | 80 | // STCA status 81 | struct CSTCAStatus { 82 | CSTCAStatus() {}; // Default constructor 83 | CSTCAStatus(string csA, string csB, CConflictStatus status, int distanceTime, int distanceNM) { 84 | CallsignA = csA; 85 | CallsignB = csB; 86 | ConflictStatus = status; 87 | DistanceAsTime = distanceTime; 88 | DistanceAsNM = distanceNM; 89 | } 90 | string CallsignA; 91 | string CallsignB; 92 | CConflictStatus ConflictStatus; 93 | int DistanceAsTime; 94 | int DistanceAsNM; 95 | }; 96 | 97 | // Describes a separation status 98 | struct CSepStatus { 99 | int DistanceAsTime; 100 | int DistanceAsNM; 101 | int AltDifference; 102 | bool IsDistanceClosing; 103 | CTrackStatus TrackStatus; 104 | CConflictStatus ConflictStatus; 105 | pair AircraftLocations; 106 | }; 107 | 108 | // Describes a window text input 109 | struct CTextInput { 110 | CTextInput() {}; // Default constructor 111 | CTextInput(int id, int type, string lbl, string content, int width, CInputState state) { 112 | Id = id; 113 | Type = type; 114 | Label = lbl; 115 | Content = content; 116 | Width = width; 117 | State = state; 118 | Error = false; 119 | } 120 | int Id; 121 | int Type; 122 | string Label; 123 | string Content; 124 | int Width; 125 | CInputState State; 126 | bool Error; 127 | }; 128 | 129 | // Describes a window check box 130 | struct CCheckBox { 131 | CCheckBox() {}; // Default constructor 132 | CCheckBox(int id, int type, string lbl, bool isChecked, CInputState state) { 133 | Id = id; 134 | Type = type; 135 | Label = lbl; 136 | IsChecked = isChecked; 137 | State = state; 138 | } 139 | int Id; 140 | int Type; 141 | string Label; 142 | bool IsChecked; 143 | CInputState State; 144 | }; 145 | 146 | // Describes a button 147 | struct CWinButton { 148 | CWinButton() {}; // Default constructor 149 | CWinButton(int id, int type, string lbl, CInputState state, int width = -1, int cycle = 0) { 150 | Id = id; 151 | Type = type; 152 | Width = width; 153 | Label = lbl; 154 | State = state; 155 | Cycle = cycle; 156 | } 157 | int Id; 158 | int Type; 159 | int Width; 160 | int Cycle; 161 | string Label; 162 | CInputState State; 163 | }; 164 | 165 | // Describes a dropdown item 166 | struct CDropDownItem { 167 | CDropDownItem() {}; // Default constructor 168 | CDropDownItem(int id, int type, string lbl, bool hovered, bool checkItem, CInputState state) { 169 | Id = id; 170 | Type = type; 171 | Label = lbl; 172 | IsHovered = hovered; 173 | IsCheckItem = checkItem; 174 | State = state; 175 | } 176 | int Id; 177 | int Type; 178 | string Label; 179 | bool IsHovered; 180 | bool IsCheckItem; 181 | CInputState State; 182 | int Width; 183 | }; 184 | 185 | // Describes a dropdown 186 | struct CDropDown { 187 | CDropDown() {}; // Default constructor 188 | CDropDown(int id, int type, string value, map* dropDownItems, CInputState state, int width = -1) { 189 | Id = id; 190 | Type = type; 191 | Value = value; 192 | int counter = 800; 193 | for (auto kv : *dropDownItems) { 194 | Items.insert(make_pair(counter, CDropDownItem(counter, type, kv.first, false, kv.second, CInputState::INACTIVE))); 195 | counter++; 196 | } 197 | State = state; 198 | Width = width; 199 | } 200 | void MakeItems(map* items) { 201 | Items.clear(); 202 | int counter = 800; 203 | for (auto kv : *items) { 204 | Items.insert(make_pair(counter, CDropDownItem(counter, Type, kv.first, false, kv.second, CInputState::INACTIVE))); 205 | counter++; 206 | } 207 | } 208 | int Id; 209 | int Type; 210 | string Value; 211 | map Items; 212 | CInputState State; 213 | int Width; 214 | }; 215 | 216 | struct CWinScrollBar { 217 | CWinScrollBar() {} 218 | CWinScrollBar(int id, int type, int cSize, int fSize, bool isX) { 219 | Id = id; 220 | Type = type; 221 | ContentSize = cSize; 222 | FrameSize = fSize; 223 | ContentRatio = (double)(FrameSize) / (double)ContentSize; 224 | IsHorizontal = isX; 225 | 226 | // Grip size (subtract 24 because buttons) 227 | // BUG: gripbox is not correct, overdraws the button, or sometimes overshoots the track 228 | GripSize = (FrameSize - 24) * ContentRatio; 229 | if (GripSize < 20) GripSize = 20; // Minimum grip size 230 | if (GripSize > FrameSize - 12) GripSize = FrameSize - 12; // Maximum grip size 231 | if (ContentRatio == 1) 232 | GripSize = FrameSize - (isX ? 12 : 24); 233 | TotalScrollableArea = ContentSize - FrameSize; 234 | PositionDelta = 0; 235 | WindowPos = 0; 236 | 237 | } 238 | int Id; 239 | int Type; 240 | int ContentSize; 241 | int FrameSize; 242 | double ContentRatio; 243 | double GripSize; 244 | double PositionDelta; 245 | double WindowPos; 246 | int TotalScrollableArea; 247 | bool IsHorizontal; 248 | }; 249 | 250 | struct CMessage { 251 | CMessage() {}; // Default constructor 252 | CMessage(int id, string to, string from, string messageRaw, string createdAt, CMessageType type) 253 | { 254 | Id = id; 255 | To = to; 256 | From = from; 257 | MessageRaw = messageRaw; 258 | CreatedAt = createdAt; 259 | Type = type; 260 | } 261 | int Id; 262 | string To; 263 | string From; 264 | string MessageRaw; 265 | string CreatedAt; 266 | CMessageType Type; 267 | }; 268 | 269 | struct CFlightRestriction { 270 | CFlightRestriction() {}; // Default constructor 271 | CRestrictionType Type; 272 | string Content; 273 | string Human; 274 | }; 275 | 276 | struct CNetworkFlightPlan { 277 | string Callsign; 278 | string Type; 279 | int AssignedLevel; 280 | int AssignedMach; 281 | string Track; 282 | string Route; 283 | string RouteEtas; 284 | string Departure; 285 | string Arrival; 286 | bool Direction; 287 | string Etd; 288 | string Selcal; 289 | bool DatalinkConnected; 290 | bool IsEquipped; 291 | string State; 292 | bool Relevant; 293 | CRadarTargetMode TargetMode; 294 | string TrackedBy; 295 | string TrackedById; 296 | string LastUpdated; 297 | }; 298 | 299 | struct CAircraftFlightPlan { 300 | CAircraftFlightPlan() {}; // Default constructor 301 | CAircraftFlightPlan( 302 | string PassedRoute, 303 | string PassedCallsign, 304 | string PassedType, 305 | string PassedDepart, 306 | string PassedDest, 307 | string PassedEtd, 308 | string PassedSELCAL, 309 | string PassedDLStatus, 310 | string PassedCommunications, 311 | string PassedSector, 312 | string PassedFlightLevel, 313 | string PassedMach, 314 | string PassedTrack, 315 | string PassedState, 316 | int PassedExitTime, 317 | bool PassedIsCleared, 318 | bool PassedIsValid 319 | ) 320 | { 321 | Callsign = PassedCallsign; 322 | Type = PassedType; 323 | Depart = PassedDepart; 324 | Dest = PassedDest; 325 | Etd = PassedEtd; 326 | SELCAL = PassedSELCAL; 327 | DLStatus = PassedDLStatus; 328 | Communications = PassedCommunications; 329 | Sector = PassedSector; 330 | FlightLevel = PassedFlightLevel; 331 | Mach = PassedMach; 332 | Track = PassedTrack; 333 | State = PassedState; 334 | ExitTime = PassedExitTime; 335 | IsCleared = PassedIsCleared; 336 | IsValid = PassedIsValid; 337 | CurrentMessage = nullptr; 338 | 339 | auto is_track = true; 340 | if (Track == "RR") 341 | { 342 | is_track = false; 343 | } 344 | else 345 | { 346 | PassedRoute = "NULL"; 347 | } 348 | } 349 | string Callsign; 350 | string Type; 351 | string Depart; 352 | string Dest; 353 | string Etd; 354 | string SELCAL; 355 | string DLStatus; 356 | string Communications; 357 | string Sector; 358 | string FlightLevel; 359 | string Mach; 360 | string Track; 361 | string State; 362 | CMessage* CurrentMessage; 363 | vector FlightHistory; 364 | vector RouteRaw; 365 | vector Route; 366 | vector Restrictions; 367 | int ExitTime; 368 | bool IsEquipped; 369 | bool IsValid = false; 370 | bool IsRelevant = true; 371 | bool IsFirstUpdate = false; // So that we can disable flight plan window until the plan has been fetched from server at least once 372 | CRadarTargetMode TargetMode = CRadarTargetMode::ADS_B; 373 | bool IsCleared = false; 374 | }; 375 | 376 | 377 | // These gotta go in here because Constants.h doesn't like it? 378 | const vector NatSM = { 379 | CWaypoint("SM15W", 50.683, -15.0), 380 | CWaypoint("SM20W", 50.833, -20.0), 381 | CWaypoint("SM30W", 50.5, -30.0), 382 | CWaypoint("SM40W", 49.266, -40.0), 383 | CWaypoint("SM50W", 47.05, -50.0), 384 | CWaypoint("SM53W", 46.166, -53.0), 385 | CWaypoint("SM60W", 44.233, -60.0), 386 | CWaypoint("SM65W", 42.766, -65.0), 387 | CWaypoint("SM67W", 42.0, -67.0) 388 | }; 389 | const vector NatSN = { 390 | CWaypoint("SN67W", 40.416667, -67.0), 391 | CWaypoint("SN65W", 41.666667, -65.0), 392 | CWaypoint("SN60W", 43.116667, -60.0), 393 | CWaypoint("SN525W", 45.166667, -52.5), 394 | CWaypoint("SN50W", 45.9, -50.0), 395 | CWaypoint("SN40W", 48.166667, -40.0), 396 | CWaypoint("SN30W", 49.433333, -30.0), 397 | CWaypoint("SN20W", 49.816667, -20.0), 398 | CWaypoint("SN15W", 49.683333, -15.0) 399 | }; 400 | const vector NatSO = { 401 | CWaypoint("SO15W", 48.666667, -15.0), 402 | CWaypoint("SO20W", 48.8, -20.0), 403 | CWaypoint("SO30W", 48.366667, -30.0), 404 | CWaypoint("SO40W", 47.066667, -40.0), 405 | CWaypoint("SO50W", 44.75, -50.0), 406 | CWaypoint("SO52W", 44.166667, -52.0), 407 | CWaypoint("SO60W", 42.0, -60.0) 408 | }; 409 | const vector NatSL = { 410 | CWaypoint("SL50W", 57.0, -50.0), 411 | CWaypoint("SL40W", 57.0, -40.0), 412 | CWaypoint("SL30W", 56.0, -30.0), 413 | CWaypoint("SL20W", 54.0, -20.0), 414 | CWaypoint("SL15W", 52.0, -15.0) 415 | }; 416 | const vector NatSP = { 417 | CWaypoint("SP20W", 46.816667, -20.0), 418 | CWaypoint("SP238W", 45.0, -23.883333), 419 | CWaypoint("SP30W", 41.6, -30.0), 420 | CWaypoint("SP40W", 34.366667, -40.0), 421 | CWaypoint("SP477W", 27.0, -47.783333), 422 | CWaypoint("SP50W", 24.633333, -50.0), 423 | CWaypoint("SP556W", 18.0, -55.65) 424 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /VatsimNAAATS/MessageWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "MessageWindow.h" 3 | #include "Styles.h" 4 | #include "Constants.h" 5 | #include "RoutesHelper.h" 6 | #include "DataHandler.h" 7 | 8 | /* THIS FILE CURRENTLY NOT USED */ 9 | 10 | using namespace Colours; 11 | 12 | const int CMessageWindow::BTN_CLOSE = 2; 13 | unordered_map CMessageWindow::OngoingMessages; 14 | unordered_map CMessageWindow::ActiveMessages; 15 | 16 | CMessageWindow::CMessageWindow(POINT topLeft) : CBaseWindow(topLeft) { 17 | // Make buttons 18 | MakeWindowItems(); 19 | 20 | // Close by default 21 | IsClosed = true; 22 | }; 23 | 24 | void CMessageWindow::MakeWindowItems() { 25 | windowButtons[BTN_CLOSE] = CWinButton(BTN_CLOSE, WIN_MSG, "Close", CInputState::INACTIVE); 26 | scrollBars[SCRL_MSGWNDW] = CWinScrollBar(SCRL_MSGWNDW, WIN_SCROLLBAR, 0, 0, false); 27 | /*CMessage msg; 28 | 29 | msg.Id = 0; 30 | msg.From = "DLH414"; 31 | msg.To = "CZQX_FSS"; 32 | msg.MessageRaw = "DLH414:CLEARANCE_REQUEST:KMCO:NULL:NEEKO:1000:A:410:81:FREETEXT"; 33 | msg.Type = CMessageType::CLEARANCE_REQ; 34 | ActiveMessages[msg.Id] = msg; 35 | 36 | msg.Id = 1; 37 | msg.From = "DLH414"; 38 | msg.To = "CZQX_FSS"; 39 | msg.MessageRaw = "DLH414:LOG_ON:CZQX_FSS"; 40 | msg.Type = CMessageType::LOG_ON; 41 | ActiveMessages[msg.Id] = msg; 42 | 43 | msg.Id = 2; 44 | msg.From = "DLH414"; 45 | msg.To = "CZQX_FSS"; 46 | msg.MessageRaw = "DLH414:REVISION_REQ:MCHG:85"; 47 | msg.Type = CMessageType::REVISION_REQ; 48 | ActiveMessages[msg.Id] = msg;*/ 49 | } 50 | 51 | void CMessageWindow::RenderWindow(CDC* dc, Graphics* g, CRadarScreen* screen) { 52 | // Save device context 53 | int iDC = dc->SaveDC(); 54 | 55 | // Create brushes 56 | CBrush darkerBrush(ScreenBlue.ToCOLORREF()); 57 | CBrush lighterBrush(WindowBorder.ToCOLORREF()); 58 | CBrush evenDarkerBrush(ButtonPressed.ToCOLORREF()); 59 | 60 | // Select title font 61 | FontSelector::SelectNormalFont(16, dc); 62 | dc->SetTextColor(Black.ToCOLORREF()); 63 | dc->SetTextAlign(TA_CENTER); 64 | 65 | // Create base window rectangle 66 | CRect windowRect(topLeft.x, topLeft.y, topLeft.x + WINSZ_MSG_WIDTH, topLeft.y + WINSZ_MSG_HEIGHT); 67 | dc->FillRect(windowRect, &darkerBrush); 68 | 69 | // Create titlebar 70 | CRect titleRect(windowRect.left, windowRect.top, windowRect.left + WINSZ_MSG_WIDTH, windowRect.top + WINSZ_TITLEBAR_HEIGHT); 71 | dc->FillRect(titleRect, &lighterBrush); 72 | dc->DrawEdge(titleRect, EDGE_RAISED, BF_BOTTOM); 73 | dc->TextOutA(titleRect.left + (WINSZ_MSG_WIDTH / 2), titleRect.top + (WINSZ_TITLEBAR_HEIGHT / 7), ("Messages (" + to_string(MessageCount) + ")").c_str()); 74 | 75 | // Create button bar 76 | CRect buttonBarRect(windowRect.left, windowRect.bottom - 50, windowRect.left + WINSZ_MSG_WIDTH, windowRect.bottom); 77 | dc->FillRect(buttonBarRect, &darkerBrush); 78 | dc->Draw3dRect(buttonBarRect, BevelLight.ToCOLORREF(), ScreenBlue.ToCOLORREF()); 79 | InflateRect(buttonBarRect, -1, -1); 80 | dc->Draw3dRect(buttonBarRect, BevelLight.ToCOLORREF(), ScreenBlue.ToCOLORREF()); 81 | 82 | // Add screen objects 83 | screen->AddScreenObject(WINDOW, "WIN_MSG", windowRect, true, ""); // So that we can't click anything under the flight plan window 84 | screen->AddScreenObject(WINDOW, "MSG", titleRect, true, ""); // Movable 85 | 86 | // Close button 87 | CCommonRenders::RenderButton(dc, screen, { buttonBarRect.left + 10, buttonBarRect.top + 10 }, 55, 30, &windowButtons.at(BTN_CLOSE)); 88 | 89 | // Font 90 | dc->SetTextColor(TextWhite.ToCOLORREF()); 91 | dc->SetTextAlign(TA_LEFT); 92 | 93 | // Drawing messages 94 | int offsetX = 5; 95 | int offsetY = 0; 96 | int contentOffsetY = 0; 97 | int totalcontent = 0; 98 | /*for (int i = 0; i < ActiveMessages.size(); i++) { 99 | // Skip displaying if the message is active 100 | //if (OngoingMessages.find(ActiveMessages[i].Id) != OngoingMessages.end()) { 101 | // continue; 102 | //} 103 | totalcontent += dc->GetTextExtent("ABC").cy + 5; 104 | 105 | // Parse the message 106 | string parsed = CUtils::ParseToPhraseology(ActiveMessages[i].MessageRaw, ActiveMessages[i].Type); 107 | 108 | // Get the wrapped text 109 | vector wrappedText; 110 | int contentSize = windowRect.Width() - (5 + 70) - 15; 111 | if (dc->GetTextExtent(parsed.c_str()).cx > contentSize) { 112 | CUtils::WrapText(dc, parsed, ' ', contentSize, &wrappedText); 113 | } 114 | 115 | totalcontent += (!wrappedText.empty() ? dc->GetTextExtent("ABCD").cy * wrappedText.size() + 15 : 5) + 5; 116 | 117 | int wrapOffsetY = 0; 118 | if (!wrappedText.empty()) { 119 | for (int i = 0; i < wrappedText.size(); i++) { 120 | wrapOffsetY += dc->GetTextExtent("ABCD").cy + 5; 121 | } 122 | } 123 | 124 | // Set messages rectangle bottom 125 | totalcontent += wrapOffsetY != 0 ? wrapOffsetY - (dc->GetTextExtent("ABC").cy + 2) : 0; 126 | }*/ 127 | for (int i = 0; i < ActiveMessages.size(); i++) { 128 | totalcontent += 50; 129 | } 130 | 131 | MessageCount = 0; 132 | for (int i = 0; i < ActiveMessages.size(); i++) { 133 | // Skip displaying if the message is active 134 | if (OngoingMessages.find(ActiveMessages[i].Id) != OngoingMessages.end()) { 135 | continue; 136 | } 137 | if (!ActiveMessages[i].MessageRaw.length()) continue; 138 | 139 | // Message count for display in window 140 | MessageCount++; 141 | 142 | int deltaoffsetY = offsetY; 143 | if (!(contentOffsetY < scrollBars[SCRL_MSGWNDW].WindowPos)) 144 | { 145 | if (!(contentOffsetY > scrollBars[SCRL_MSGWNDW].WindowPos + scrollBars[SCRL_MSGWNDW].FrameSize - 25)) 146 | { 147 | CRect message(windowRect.left, windowRect.top + WINSZ_TITLEBAR_HEIGHT + offsetY, windowRect.right, 0); // Set to 0 here 148 | offsetY += dc->GetTextExtent("ABC").cy + 5; 149 | 150 | // Parse the message 151 | string parsed = CUtils::ParseToPhraseology(ActiveMessages[i].MessageRaw, ActiveMessages[i].Type, ActiveMessages[i].From); 152 | 153 | // Get the wrapped text 154 | vector wrappedText; 155 | int contentSize = windowRect.Width() - (offsetX + 70) - 15; 156 | if (dc->GetTextExtent(parsed.c_str()).cx > contentSize) { 157 | CUtils::WrapText(dc, parsed, ' ', contentSize, &wrappedText); 158 | } 159 | 160 | // Set messages rectangle bottom 161 | message.bottom = windowRect.top + WINSZ_TITLEBAR_HEIGHT + (!wrappedText.empty() ? dc->GetTextExtent("ABCD").cy * wrappedText.size() + 15 + deltaoffsetY : offsetY) + 5; 162 | 163 | if (ActiveMessages[i].Id == SelectedMessage) { 164 | dc->FillRect(message, &evenDarkerBrush); 165 | } 166 | 167 | // Text 'from' 168 | dc->TextOutA(message.left + offsetX, message.top + 5, ActiveMessages[i].From.c_str()); 169 | offsetX += 70; 170 | 171 | // If the text is wrapped 172 | int wrapOffsetY = 0; 173 | if (!wrappedText.empty()) { 174 | // Iterate to display 175 | wrapOffsetY = 5; 176 | for (int i = 0; i < wrappedText.size(); i++) { 177 | // Write the message 178 | dc->TextOutA(message.left + offsetX, message.top + wrapOffsetY, wrappedText[i].c_str()); 179 | wrapOffsetY += dc->GetTextExtent("ABCD").cy + 5; 180 | } 181 | } 182 | else { 183 | // Write without iterating 184 | dc->TextOutA(message.left + offsetX, message.top + 5, parsed.c_str()); 185 | } 186 | 187 | // Add screen object for message 188 | screen->AddScreenObject(ACTV_MESSAGE, to_string(ActiveMessages[i].Id).c_str(), message, false, ""); 189 | 190 | // Reset X offset 191 | offsetX = 5; 192 | 193 | // Add wrapped text size to y offset 194 | offsetY += wrapOffsetY != 0 ? wrapOffsetY - (dc->GetTextExtent("ABC").cy + 2) : 0; 195 | } 196 | } 197 | //contentOffsetY += 50; 198 | //contentOffsetY += (offsetY - deltaoffsetY); 199 | contentOffsetY += (offsetY - deltaoffsetY) == 0 ? 50 : (offsetY - deltaoffsetY); 200 | } 201 | 202 | // Scroll bar values 203 | if (scrollBars[SCRL_MSGWNDW].FrameSize == 0 || (scrollBars[SCRL_MSGWNDW].ContentSize != contentOffsetY && scrollBars[SCRL_MSGWNDW].PositionDelta == 0 && scrollBars[SCRL_MSGWNDW].ContentRatio != 1)) 204 | { 205 | int framebox = windowRect.Height() - 65; 206 | if (contentOffsetY == 0) 207 | contentOffsetY = framebox; // ratio 1:1 208 | scrollBars[SCRL_MSGWNDW] = CWinScrollBar(SCRL_MSGWNDW, WIN_SCROLLBAR, contentOffsetY, framebox, false); 209 | if (contentOffsetY != framebox) 210 | { 211 | scrollBars[SCRL_MSGWNDW].GripSize -= 30; // temporary fix for grip bug 212 | scrollBars[SCRL_MSGWNDW].TotalScrollableArea = framebox - scrollBars[SCRL_MSGWNDW].GripSize; 213 | } 214 | } 215 | 216 | // Draw scroll bars 217 | CCommonRenders::RenderScrollBar(dc, g, screen, { windowRect.right - 12, windowRect.top + 20 }, &scrollBars[SCRL_MSGWNDW]); 218 | 219 | // Create borders 220 | dc->DrawEdge(windowRect, EDGE_SUNKEN, BF_RECT); 221 | InflateRect(windowRect, 1, 1); 222 | dc->Draw3dRect(windowRect, WindowBorder.ToCOLORREF(), WindowBorder.ToCOLORREF()); 223 | InflateRect(windowRect, 1, 1); 224 | dc->DrawEdge(windowRect, EDGE_RAISED, BF_RECT); 225 | 226 | // Cleanup 227 | DeleteObject(darkerBrush); 228 | DeleteObject(lighterBrush); 229 | 230 | // Restore device context 231 | dc->RestoreDC(iDC); 232 | } 233 | 234 | void CMessageWindow::ButtonUp(int id, CRadarScreen* screen) { 235 | // Press button 236 | windowButtons.find(id)->second.State = CInputState::INACTIVE; 237 | SelectedMessage = -1; 238 | } 239 | 240 | void CMessageWindow::ButtonDown(int id) { 241 | // Press button 242 | windowButtons.find(id)->second.State = CInputState::ACTIVE; 243 | } 244 | 245 | void CMessageWindow::ButtonPress(int id) { 246 | 247 | } 248 | 249 | void CMessageWindow::ButtonDoubleClick(CRadarScreen* screen, int id, CFlightPlanWindow* fltPlnWin) { 250 | // Message pointer 251 | CMessage* msg = &ActiveMessages[id]; 252 | 253 | // Get rid of selected message so if requeued the click highlight doesn't reappear 254 | SelectedMessage = -1; 255 | 256 | if (!screen->GetPlugIn()->FlightPlanSelect(msg->From.c_str()).IsValid()) { 257 | ActiveMessages.erase(id); 258 | return; 259 | } 260 | if (msg->Type == CMessageType::LOG_ON || msg->Type == CMessageType::TRANSFER) { 261 | fltPlnWin->Instantiate(screen, msg->From, msg); 262 | fltPlnWin->IsClosed = false; 263 | fltPlnWin->IsTransferOpen = true; 264 | screen->GetPlugIn()->SetASELAircraft(screen->GetPlugIn()->FlightPlanSelect(msg->From.c_str())); 265 | OngoingMessages[msg->Id] = msg; 266 | } 267 | else if (msg->Type == CMessageType::TRANSFER_ACCEPT || 268 | msg->Type == CMessageType::WILCO || 269 | msg->Type == CMessageType::UNABLE || 270 | msg->Type == CMessageType::ROGER) { 271 | OngoingMessages.erase(id); 272 | ActiveMessages.erase(id); 273 | } 274 | else if (msg->Type == CMessageType::CLEARANCE_REQ) { 275 | /// Parse the message 276 | // Split string 277 | vector tokens; 278 | CUtils::StringSplit(msg->MessageRaw, ':', &tokens); 279 | 280 | // Values 281 | string arrival; 282 | string track; 283 | string route = ""; 284 | string ep; 285 | string epEst; 286 | string level; 287 | string speed; 288 | // Loop tokens 289 | arrival = tokens[2]; 290 | route = tokens[3] != "NULL" && tokens[6] == "RR" ? tokens[3] : ""; 291 | track = tokens[6] != "RR" ? tokens[6] : "RR"; 292 | ep = tokens[4]; 293 | epEst = tokens[5]; 294 | level = tokens[7]; 295 | speed = tokens[8]; 296 | // Instantiate flight plan window 297 | fltPlnWin->Instantiate(screen, msg->From, msg); 298 | fltPlnWin->IsData = true; 299 | fltPlnWin->SetButtonState(CFlightPlanWindow::BTN_PROBE, CInputState::INACTIVE); 300 | fltPlnWin->primedPlan->Mach = speed; 301 | fltPlnWin->primedPlan->Track = track; 302 | fltPlnWin->primedPlan->FlightLevel = level; 303 | fltPlnWin->primedPlan->Dest = arrival; 304 | fltPlnWin->primedPlan->State = "UA"; 305 | 306 | // Instantiate flight plan variables 307 | fltPlnWin->SetTextValue(screen, CFlightPlanWindow::TXT_SPD, speed); 308 | fltPlnWin->SetTextValue(screen, CFlightPlanWindow::TXT_LEVEL, level); 309 | fltPlnWin->SetTextValue(screen, CFlightPlanWindow::TXT_DEST, arrival); 310 | fltPlnWin->SetTextValue(screen, CFlightPlanWindow::TXT_STATE, "UA"); 311 | if (track != "RR") { 312 | fltPlnWin->SetTextValue(screen, CFlightPlanWindow::TXT_TCK, track); 313 | } 314 | else { 315 | fltPlnWin->SetTextValue(screen, CFlightPlanWindow::TXT_RTE, route); 316 | } 317 | screen->GetPlugIn()->SetASELAircraft(screen->GetPlugIn()->FlightPlanSelect(msg->From.c_str())); 318 | OngoingMessages[msg->Id] = msg; 319 | } 320 | else if (msg->Type == CMessageType::REVISION_REQ) { 321 | // Instantiate flight plan window 322 | fltPlnWin->Instantiate(screen, msg->From, msg); 323 | } 324 | } 325 | 326 | void CMessageWindow::ButtonUnpress(int id) { 327 | 328 | } 329 | 330 | void CMessageWindow::SetButtonState(int id, CInputState state) { 331 | 332 | } -------------------------------------------------------------------------------- /VatsimNAAATS/VatsimNAAATS.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {8E1E2CE6-DF6C-41D3-8BBF-8803D826031D} 24 | MFCDLLProj 25 | VatsimNAAATS 26 | 8.1 27 | 28 | 29 | 30 | DynamicLibrary 31 | true 32 | v140 33 | MultiByte 34 | Static 35 | 36 | 37 | DynamicLibrary 38 | false 39 | v140 40 | false 41 | MultiByte 42 | Static 43 | 44 | 45 | DynamicLibrary 46 | true 47 | v142 48 | Unicode 49 | Dynamic 50 | 51 | 52 | DynamicLibrary 53 | false 54 | v142 55 | true 56 | Unicode 57 | Dynamic 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | true 79 | 80 | 81 | true 82 | 83 | 84 | false 85 | 86 | 87 | false 88 | 89 | 90 | 91 | Create 92 | Level3 93 | true 94 | WIN32;_WINDOWS;_DEBUG;_USRDLL;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;CURL_STATICLIB;%(PreprocessorDefinitions) 95 | pch.h 96 | $(ProjectDir)\..\lib\include;%(AdditionalIncludeDirectories) 97 | false 98 | false 99 | 100 | 101 | Windows 102 | .\VatsimNAAATS.def 103 | $(ProjectDir)..\lib\EuroScopePlugInDll.lib;Normaliz.lib;Ws2_32.lib;Wldap32.lib;Crypt32.lib;advapi32.lib;gdiplus.lib;%(AdditionalDependencies) 104 | 105 | 106 | false 107 | _DEBUG;%(PreprocessorDefinitions) 108 | 109 | 110 | 0x0409 111 | _DEBUG;%(PreprocessorDefinitions) 112 | $(IntDir);%(AdditionalIncludeDirectories) 113 | 114 | 115 | 116 | 117 | Use 118 | Level3 119 | true 120 | _WINDOWS;_DEBUG;_USRDLL;%(PreprocessorDefinitions) 121 | pch.h 122 | 123 | 124 | Windows 125 | .\VatsimNAAATS.def 126 | 127 | 128 | false 129 | _DEBUG;%(PreprocessorDefinitions) 130 | 131 | 132 | 0x0409 133 | _DEBUG;%(PreprocessorDefinitions) 134 | $(IntDir);%(AdditionalIncludeDirectories) 135 | 136 | 137 | 138 | 139 | Create 140 | Level3 141 | true 142 | true 143 | true 144 | WIN32;_WINDOWS;_DEBUG;_USRDLL;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;CURL_STATICLIB;%(PreprocessorDefinitions) 145 | pch.h 146 | $(ProjectDir)\..\lib\include;%(AdditionalIncludeDirectories) 147 | false 148 | MultiThreaded 149 | 150 | 151 | Windows 152 | true 153 | true 154 | .\VatsimNAAATS.def 155 | $(ProjectDir)\..\lib\EuroScopePlugInDll.lib;Normaliz.lib;Ws2_32.lib;Wldap32.lib;Crypt32.lib;advapi32.lib;gdiplus.lib;%(AdditionalDependencies) 156 | false 157 | 158 | 159 | false 160 | NDEBUG;%(PreprocessorDefinitions) 161 | 162 | 163 | 0x0409 164 | NDEBUG;%(PreprocessorDefinitions) 165 | $(IntDir);%(AdditionalIncludeDirectories) 166 | 167 | 168 | 169 | 170 | Use 171 | Level3 172 | true 173 | true 174 | true 175 | _WINDOWS;NDEBUG;_USRDLL;%(PreprocessorDefinitions) 176 | pch.h 177 | 178 | 179 | Windows 180 | true 181 | true 182 | .\VatsimNAAATS.def 183 | 184 | 185 | false 186 | NDEBUG;%(PreprocessorDefinitions) 187 | 188 | 189 | 0x0409 190 | NDEBUG;%(PreprocessorDefinitions) 191 | $(IntDir);%(AdditionalIncludeDirectories) 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | -------------------------------------------------------------------------------- /VatsimNAAATS/RoutesHelper.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "RoutesHelper.h" 3 | #include "DataHandler.h" 4 | 5 | map CRoutesHelper::CurrentTracks; 6 | 7 | string CRoutesHelper::CurrentTMI = ""; 8 | 9 | vector CRoutesHelper::ActiveRoutes; 10 | 11 | bool CRoutesHelper::GetRoute(CRadarScreen* screen, vector* routeVector, string callsign, CAircraftFlightPlan* copy) {\ 12 | try { 13 | // Get the flight plan 14 | CAircraftFlightPlan* fp = copy != nullptr ? copy : CDataHandler::GetFlightData(callsign); 15 | 16 | 17 | // Check validity 18 | if (!fp->IsValid || fp->Route.size() == 0) { 19 | return false; 20 | } 21 | 22 | // Get target 23 | CRadarTarget target = screen->GetPlugIn()->RadarTargetSelect(callsign.c_str()); 24 | 25 | // Get aircraft direction 26 | bool direction = CUtils::GetAircraftDirection(target.GetPosition().GetReportedHeadingTrueNorth()); 27 | 28 | // Loop through each route item 29 | int totalDistance = 0; 30 | for (int idx = 0; idx < fp->Route.size(); idx++) { 31 | // Create position 32 | CRoutePosition position; 33 | 34 | // Fix 35 | position.Fix = fp->Route[idx].Name; 36 | position.PositionRaw = fp->Route[idx].Position; 37 | 38 | // Get estimate 39 | if (!direction) { // Westbound 40 | if (target.GetPosition().GetPosition().m_Longitude > fp->Route[idx].Position.m_Longitude) { 41 | if (totalDistance == 0) { 42 | // Calculate distance from aircraft 43 | totalDistance += target.GetPosition().GetPosition().DistanceTo(fp->Route[idx].Position); 44 | position.DistanceFromLastPoint = target.GetPosition().GetPosition().DistanceTo(fp->Route[idx].Position); 45 | } 46 | else { 47 | // Calculate distance point to point 48 | totalDistance += fp->Route.at(idx - 1).Position.DistanceTo(fp->Route.at(idx).Position); 49 | position.DistanceFromLastPoint = fp->Route.at(idx - 1).Position.DistanceTo(fp->Route.at(idx).Position); 50 | } 51 | position.Estimate = CUtils::ParseZuluTime(false, CUtils::GetTimeDistanceSpeed((int)round(totalDistance), target.GetPosition().GetReportedGS())); 52 | } 53 | else { 54 | position.Estimate = "--"; 55 | position.DistanceFromLastPoint = 0; 56 | } 57 | } 58 | else { // Eastbound 59 | if (target.GetPosition().GetPosition().m_Longitude < fp->Route[idx].Position.m_Longitude) { 60 | if (totalDistance == 0) { 61 | // Calculate distance from aircraft 62 | totalDistance += target.GetPosition().GetPosition().DistanceTo(fp->Route[idx].Position); 63 | position.DistanceFromLastPoint = target.GetPosition().GetPosition().DistanceTo(fp->Route[idx].Position); 64 | } 65 | else { 66 | // Calculate distance point to point 67 | totalDistance += fp->Route.at(idx - 1).Position.DistanceTo(fp->Route.at(idx).Position); 68 | position.DistanceFromLastPoint = fp->Route.at(idx - 1).Position.DistanceTo(fp->Route.at(idx).Position); 69 | } 70 | position.Estimate = CUtils::ParseZuluTime(false, CUtils::GetTimeDistanceSpeed((int)round(totalDistance), target.GetPosition().GetReportedGS())); 71 | } 72 | else { 73 | position.Estimate = "--"; 74 | position.DistanceFromLastPoint = 0; 75 | } 76 | } 77 | 78 | // Altitude 79 | position.FlightLevel = target.GetPosition().GetFlightLevel() / 100; 80 | 81 | // Add the position 82 | routeVector->push_back(position); 83 | } 84 | } 85 | catch (std::exception & ex) { 86 | CLogger::DebugLog(screen, "An exception occurred. " + *ex.what()); 87 | CLogger::Log(CLogType::ERR, "An error occurred. Callsign: " + callsign + "\nVerbose details: " + *ex.what(), "CRoutesHelper::GetRoute"); 88 | return false; 89 | } 90 | 91 | return true; 92 | } 93 | 94 | void CRoutesHelper::InitialiseRoute(void* args) { 95 | // Convert args 96 | CUtils::CAsyncData* data = (CUtils::CAsyncData*) args; 97 | try { 98 | // Flight plan 99 | CAircraftFlightPlan* fp = data->FP != nullptr ? data->FP : CDataHandler::GetFlightData(data->Callsign); 100 | 101 | // Final route vector 102 | vector parsedRoute; 103 | 104 | // Track 105 | string trackReturned = ""; 106 | 107 | // First we check if they have a route string 108 | if (fp != nullptr && !fp->RouteRaw.empty() && fp->RouteRaw.size() > 0) { // Get their route as per the route string 109 | // We check now if they have a track 110 | if (fp->Track != "RR" && CurrentTracks.find(fp->Track) != CurrentTracks.end()) { 111 | if (fp->Track.size() < 2 ) { 112 | for (int i = 0; i < CurrentTracks.find(fp->Track)->second.RouteRaw.size(); i++) { 113 | CWaypoint point; 114 | point.Name = CurrentTracks.find(fp->Track)->second.Route[i]; 115 | point.Position = CurrentTracks.find(fp->Track)->second.RouteRaw[i]; 116 | parsedRoute.push_back(point); 117 | } 118 | } 119 | else { 120 | // Concorde route 121 | if (trackReturned.size() == 2) { 122 | if (trackReturned == "SM") { 123 | parsedRoute = NatSM; 124 | } 125 | else if (trackReturned == "SN") { 126 | parsedRoute = NatSN; 127 | } 128 | else if (trackReturned == "SP") { 129 | parsedRoute = NatSP; 130 | } 131 | else if (trackReturned == "SL") { 132 | parsedRoute = NatSL; 133 | } 134 | else { 135 | parsedRoute = NatSO; 136 | } 137 | } 138 | } 139 | } 140 | else { // It's a random routing 141 | for (int i = 0; i < fp->RouteRaw.size(); i++) { 142 | // Waypoint obj 143 | CWaypoint point; 144 | 145 | // We check whether there are any numbers in the item 146 | bool isAllAlpha = true; 147 | for (int j = 0; j < fp->RouteRaw[i].size(); j++) { 148 | if (isdigit(fp->RouteRaw[i].at(j))) { 149 | isAllAlpha = false; 150 | } 151 | } 152 | 153 | // If it's a waypoint we need to search the sector file for the reference 154 | if (isAllAlpha) { 155 | // Get sector file 156 | data->Screen->GetPlugIn()->SelectActiveSectorfile(); 157 | CSectorElement fix; // Fixes element 158 | 159 | // Select waypoint 160 | try { 161 | for (fix = data->Screen->GetPlugIn()->SectorFileElementSelectFirst(EuroScopePlugIn::SECTOR_ELEMENT_FIX); 162 | fix.IsValid(); 163 | fix = data->Screen->GetPlugIn()->SectorFileElementSelectNext(fix, EuroScopePlugIn::SECTOR_ELEMENT_FIX)) { 164 | string fixName = fix.GetName(); 165 | if (!strcmp(fixName.c_str(), fp->RouteRaw.at(i).c_str())) { 166 | break; 167 | } 168 | } 169 | } 170 | catch (std::out_of_range ex) { 171 | // Leave blank 172 | } 173 | 174 | // Check here in case not found 175 | CPosition pos; 176 | if (fp->RouteRaw[i] == fix.GetName() && fix.GetPosition(&pos, 0)) { // If found then add 177 | point.Name = fp->RouteRaw[i]; 178 | point.Position = pos; 179 | 180 | } 181 | else { // If not then set the default (highly unlikely but a fallback just in case) 182 | pos.m_Latitude = 0.0; 183 | pos.m_Longitude = 0.0; 184 | point.Name = fp->RouteRaw[i]; 185 | point.Position = pos; 186 | } 187 | } 188 | else { 189 | // Make position from the string lat and lon 190 | CPosition pos; 191 | pos.m_Latitude = stod(fp->RouteRaw[i].substr(0, 2)); 192 | pos.m_Longitude = -(stod(fp->RouteRaw[i].substr(3, 2))); 193 | point.Name = fp->RouteRaw[i]; 194 | point.Position = pos; 195 | } 196 | 197 | // Append the waypoint object 198 | parsedRoute.push_back(point); 199 | } 200 | } 201 | } 202 | else { // We get the route as per their VATSIM flight plan if no route string 203 | // Target, flight plan and route 204 | CRadarTarget target = data->Screen->GetPlugIn()->RadarTargetSelect(data->Callsign.c_str()); 205 | CFlightPlan fpData = data->Screen->GetPlugIn()->FlightPlanSelect(target.GetCallsign()); 206 | CFlightPlanExtractedRoute route = fpData.GetExtractedRoute(); 207 | 208 | // Get NAT track (if they are on it) 209 | trackReturned = OnNatTrack(data->Screen, data->Callsign.c_str()); 210 | CTrack track; 211 | if (trackReturned != "") { // If on a track 212 | // Check if it is concorde first 213 | if (trackReturned.size() == 1) { 214 | bool loopBreak = false; 215 | for (auto kv : CRoutesHelper::CurrentTracks) { 216 | if (kv.first == trackReturned) { // Assign track to the returned box 217 | track = kv.second; 218 | loopBreak = true; 219 | break; 220 | } 221 | } 222 | if (!loopBreak) { // If for some reason the pilot's track doesn't exist, ignore it 223 | trackReturned = ""; 224 | } 225 | // Track id 226 | fp->Track = trackReturned; 227 | } 228 | } 229 | 230 | // If on track 231 | bool routeFetched = false; 232 | if (trackReturned != "") { 233 | // Check concorde 234 | if (trackReturned.size() == 2) { 235 | if (trackReturned == "SM") { 236 | parsedRoute = NatSM; 237 | routeFetched = true; 238 | } 239 | else if (trackReturned == "SN") { 240 | parsedRoute = NatSN; 241 | routeFetched = true; 242 | } 243 | else if (trackReturned == "SP") { 244 | parsedRoute = NatSP; 245 | routeFetched = true; 246 | } 247 | else if (trackReturned == "SL") { 248 | parsedRoute = NatSL; 249 | routeFetched = true; 250 | } 251 | else { 252 | parsedRoute = NatSO; 253 | routeFetched = true; 254 | } 255 | } 256 | 257 | if (!routeFetched) { 258 | for (int i = 0; i < track.RouteRaw.size(); i++) { 259 | // Make waypoint 260 | CWaypoint point; 261 | point.Name = track.Route[i]; 262 | point.Position = track.RouteRaw[i]; 263 | 264 | // Add to route vector 265 | parsedRoute.push_back(point); 266 | } 267 | } 268 | } 269 | else { 270 | // Track id 271 | fp->Track = "RR"; 272 | 273 | // Find our entry and exit points 274 | int entryPoint = -1; 275 | int exitPoint = -1; 276 | bool direction = CUtils::GetAircraftDirection(target.GetPosition().GetReportedHeadingTrueNorth()); 277 | for (int i = 0; i < route.GetPointsNumber(); i++) { 278 | if (entryPoint == -1) { // Check entry point 279 | if (CUtils::IsEntryPoint(string(route.GetPointName(i)), direction ? true : false)) { 280 | entryPoint = i; 281 | continue; 282 | } 283 | } 284 | if (exitPoint == -1) { // Exit point 285 | if (CUtils::IsExitPoint(string(route.GetPointName(i)), direction ? true : false)) { 286 | exitPoint = i; 287 | break; 288 | } 289 | } 290 | } 291 | 292 | // Entry and exit points 293 | int start = entryPoint == -1 ? route.GetPointsCalculatedIndex() : entryPoint; 294 | int stop = exitPoint == -1 ? route.GetPointsNumber() : exitPoint + 1; 295 | 296 | // First add the aircraft position if entry point is -1 297 | if (entryPoint == -1) { 298 | // Waypoint 299 | CWaypoint point; 300 | point.Name = "AIRCRAFT"; 301 | point.Position = target.GetPosition().GetPosition(); 302 | 303 | // Add to the vector 304 | parsedRoute.push_back(point); 305 | } 306 | 307 | // Get entry and exit points 308 | for (int i = start; i < stop; i++) { 309 | // First check if position is within reasonable longitudinal and lateral bounds 310 | if (route.GetPointPosition(i).m_Longitude >= -65 && route.GetPointPosition(i).m_Longitude <= -5 311 | && route.GetPointPosition(i).m_Latitude >= 40 && route.GetPointPosition(i).m_Latitude <= 70) { 312 | // Now make the waypoint 313 | CWaypoint point; 314 | point.Name = CUtils::ConvertCoordinateFormat(route.GetPointName(i), 0); 315 | point.Position = route.GetPointPosition(i); 316 | 317 | // Add waypoint to parsed vector 318 | parsedRoute.push_back(point); 319 | } 320 | } 321 | } 322 | } 323 | 324 | // Return the vector 325 | CDataHandler::SetRoute(data->Callsign, &parsedRoute, fp->Track, data->FP != nullptr ? data->FP : nullptr); 326 | 327 | // Cleanup 328 | delete args; 329 | } 330 | catch (std::exception & ex) { 331 | CLogger::DebugLog(data->Screen, "An exception occurred. " + *ex.what()); 332 | CLogger::Log(CLogType::ERR, "An error occurred. Callsign: " + data->Callsign + "\nVerbose details: " + *ex.what(), "CRoutesHelper::InitialiseRoute"); 333 | } 334 | } 335 | 336 | int CRoutesHelper::ParseRoute(CRadarScreen* screen, string callsign, string rawInput, bool isTrack, CAircraftFlightPlan* copy) { 337 | try { 338 | // Return vector 339 | vector route; 340 | 341 | // Track 342 | string track; 343 | 344 | // Deal with track 345 | if (isTrack) { 346 | if (rawInput.size() < 3) { 347 | if (CRoutesHelper::CurrentTracks.find(rawInput) != CRoutesHelper::CurrentTracks.end()) { 348 | route = CRoutesHelper::CurrentTracks.at(rawInput).Route; 349 | track = CRoutesHelper::CurrentTracks.at(rawInput).Identifier; 350 | } 351 | else { 352 | return 1; 353 | } 354 | } 355 | else { 356 | // Check concorde 357 | if (rawInput == "SM") { 358 | track = rawInput; 359 | for (int i = 0; i < NatSM.size(); i++) { 360 | 361 | } 362 | } 363 | else if (rawInput == "SN") { 364 | track = rawInput; 365 | for (int i = 0; i < NatSN.size(); i++) { 366 | } 367 | } 368 | else if (rawInput == "SP") { 369 | track = rawInput; 370 | for (int i = 0; i < NatSP.size(); i++) { 371 | } 372 | } 373 | else if (rawInput == "SL") { 374 | track = rawInput; 375 | for (int i = 0; i < NatSL.size(); i++) { 376 | } 377 | } 378 | else if (rawInput == "SO") { 379 | track = rawInput; 380 | for (int i = 0; i < NatSO.size(); i++) { 381 | } 382 | } 383 | else { 384 | return 1; 385 | } 386 | } 387 | } 388 | else { 389 | /// Validation 390 | // Tokens for split string 391 | vector tokens; 392 | 393 | // String stream 394 | stringstream stream(rawInput); 395 | 396 | // Intermediate value 397 | string intermediate; 398 | 399 | track = "RR"; 400 | 401 | // Tokenise the string 402 | while (getline(stream, intermediate, ' ')) 403 | { 404 | tokens.push_back(intermediate); 405 | } 406 | 407 | // Loop the tokens 408 | for (int i = 0; i < tokens.size(); i++) { 409 | // Check if digits 410 | bool isAllAlpha = true; 411 | for (int j = 0; j < tokens.at(i).size(); j++) { 412 | if (isdigit(tokens.at(i).at(j))) { 413 | isAllAlpha = false; 414 | } 415 | } 416 | 417 | // If waypoint check the size 418 | if (isAllAlpha) { 419 | // Reject if greater or less than 5 420 | if (tokens.at(i).size() < 5 || tokens.at(i).size() > 5) { 421 | return 1; 422 | } 423 | else { 424 | // Otherwise make uppercase and push back 425 | string waypoint; 426 | for (int j = 0; j < tokens.at(i).size(); j++) { 427 | waypoint += toupper(tokens.at(i)[j]); 428 | } 429 | route.push_back(waypoint); 430 | } 431 | } 432 | else { // It's a coordinate 433 | if (tokens.at(i).size() < 5 || tokens.at(i).size() > 5) { 434 | return 1; 435 | } 436 | else { 437 | // Check manually 438 | if (!isdigit(tokens.at(i)[0])) 439 | return 1; 440 | if (!isdigit(tokens.at(i)[1])) 441 | return 1; 442 | if (tokens.at(i)[2] != '/') 443 | return 1; 444 | if (!isdigit(tokens.at(i)[3])) 445 | return 1; 446 | if (!isdigit(tokens.at(i)[4])) 447 | return 1; 448 | 449 | // We got here so push it 450 | route.push_back(tokens.at(i)); 451 | } 452 | } 453 | } 454 | } 455 | 456 | // We got here, so set the route and return success code 457 | if (copy != nullptr) { 458 | copy->Track = track; 459 | copy->RouteRaw.clear(); 460 | for (int i = 0; i < route.size(); i++) { 461 | if (route[i] == "AIRCRAFT") 462 | route.at(i).erase(); 463 | continue; 464 | copy->RouteRaw.push_back(route[i]); 465 | } 466 | } 467 | else { 468 | CDataHandler::GetFlightData(callsign)->Track = track; 469 | CDataHandler::GetFlightData(callsign)->RouteRaw.clear(); 470 | for (int i = 0; i < route.size(); i++) { 471 | if (route[i] == "AIRCRAFT") { 472 | route.at(i).erase(); 473 | continue; 474 | } 475 | 476 | CDataHandler::GetFlightData(callsign)->RouteRaw.push_back(route[i]); 477 | } 478 | } 479 | 480 | } 481 | catch (std::exception & ex) { 482 | CLogger::DebugLog(screen, "An exception occurred. " + *ex.what()); 483 | CLogger::Log(CLogType::ERR, "An error occurred. Callsign: " + callsign + "\nVerbose details: " + *ex.what(), "CRoutesHelper::ParseRoute"); 484 | return 1; 485 | } 486 | 487 | return 0; 488 | } 489 | 490 | string CRoutesHelper::OnNatTrack(CRadarScreen* screen, string callsign) { 491 | try { 492 | // Get flight plan 493 | CFlightPlan fp = screen->GetPlugIn()->FlightPlanSelect(callsign.c_str()); 494 | 495 | // Get route and begin search 496 | string route = fp.GetFlightPlanData().GetRoute(); 497 | size_t found = route.find(string(" NAT")); 498 | // If found 499 | if (found != string::npos) { 500 | // Make sure that it's not a waypoint starting with NAT (check character count) 501 | while (found != string::npos && route.at(found + 5) != 0x20) { 502 | route = route.substr(found + 5, route.size() - found + 5 - 1); 503 | found = route.find(string(" NAT")); 504 | } 505 | if (route.at(found + 5) == 0x20) { // If it was found (found + 5 was a space character) 506 | // Get the ID and return 507 | string trackId; 508 | trackId.push_back(route.at(found + 4)); 509 | 510 | // Check if it exists 511 | if (CurrentTracks.find(trackId) != CurrentTracks.end()) 512 | return trackId; 513 | else 514 | return ""; 515 | } 516 | else if (route.at(found + 5) == 0x4c || 517 | route.at(found + 5) == 0x4d || route.at(found + 5) == 0x4e || 518 | route.at(found + 5) == 0x4f || route.at(found + 5) == 0x50) { // A letter matching a Concorde track was found 519 | 520 | // Get the ID and return 521 | string trackId; 522 | trackId.push_back(route.at(found + 4) + route.at(found + 5)); 523 | 524 | // Check if it exists 525 | if (CurrentTracks.find(trackId) != CurrentTracks.end()) 526 | return trackId; 527 | else 528 | return ""; 529 | } 530 | else { 531 | return ""; 532 | } 533 | } 534 | else { // Not on a NAT 535 | return ""; 536 | } 537 | } 538 | catch (std::exception & ex) { 539 | CLogger::DebugLog(screen, "An exception occurred. " + *ex.what()); 540 | CLogger::Log(CLogType::ERR, "An error occurred. Callsign: " + callsign + "\nVerbose details: " + *ex.what(), "CRoutesHelper::OnNatTrack"); 541 | return ""; 542 | } 543 | } -------------------------------------------------------------------------------- /VatsimNAAATS/MenuBar.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "MenuBar.h" 3 | #include "Constants.h" 4 | #include "MenuBar.h" 5 | #include "Styles.h" 6 | #include "Utils.h" 7 | #include "CommonRenders.h" 8 | #include "Overlays.h" 9 | 10 | using namespace Colours; 11 | 12 | CMenuBar::CMenuBar() { 13 | // Button defaults 14 | buttons[BTN_SETUP] = CWinButton(BTN_SETUP, MENBAR, "Setup", CInputState::DISABLED, 46); 15 | buttons[BTN_NOTEPAD] = CWinButton(BTN_NOTEPAD, MENBAR, "NotePad", CInputState::DISABLED, 78); 16 | buttons[BTN_ADSC] = CWinButton(BTN_ADSC, MENBAR, "Flight Data", CInputState::INACTIVE, 80); 17 | buttons[BTN_TCKINFO] = CWinButton(BTN_TCKINFO, MENBAR, "Track Info", CInputState::INACTIVE, 78); 18 | buttons[BTN_MISC] = CWinButton(BTN_MISC, MENBAR, "Misc", CInputState::DISABLED, 41); 19 | buttons[BTN_MESSAGE] = CWinButton(BTN_MESSAGE, MENBAR, "Message", CInputState::DISABLED, 75); 20 | buttons[BTN_TAGS] = CWinButton(BTN_TAGS, MENBAR, "Tags", CInputState::ACTIVE, 46); 21 | buttons[BTN_FLIGHTPLAN] = CWinButton(BTN_FLIGHTPLAN, MENBAR, "Flight Plan", CInputState::DISABLED, 78); 22 | buttons[BTN_DETAILED] = CWinButton(BTN_DETAILED, MENBAR, "ASEL Dtld", CInputState::INACTIVE, 80); 23 | buttons[BTN_AREASEL] = CWinButton(BTN_AREASEL, MENBAR, "Area Sel", CInputState::DISABLED, 83); 24 | buttons[BTN_TCKCTRL] = CWinButton(BTN_TCKCTRL, MENBAR, "Tck Control", CInputState::DISABLED, 88); 25 | buttons[BTN_OVERLAYS] = CWinButton(BTN_OVERLAYS, MENBAR, "Overlays", CInputState::INACTIVE, 73); 26 | buttons[BTN_TYPESEL] = CWinButton(BTN_TYPESEL, MENBAR, "Select", CInputState::DISABLED, 68); 27 | buttons[BTN_ALTFILT] = CWinButton(BTN_ALTFILT, MENBAR, "Alt Filter", CInputState::INACTIVE, 86); 28 | buttons[BTN_HALO] = CWinButton(BTN_HALO, MENBAR, "Halo 5", CInputState::INACTIVE, 68, 0); 29 | buttons[BTN_RBL] = CWinButton(BTN_RBL, MENBAR, "RBL", CInputState::INACTIVE, 48); 30 | buttons[BTN_RINGS] = CWinButton(BTN_RINGS, MENBAR, "Rings 1", CInputState::DISABLED, 73, 0); 31 | buttons[BTN_QDM] = CWinButton(BTN_QDM, MENBAR, "QDM", CInputState::INACTIVE, 43); 32 | buttons[BTN_PTL] = CWinButton(BTN_PTL, MENBAR, "PTL 5", CInputState::INACTIVE, 68, 0); 33 | buttons[BTN_PIV] = CWinButton(BTN_PIV, MENBAR, "PIV", CInputState::INACTIVE, 48); 34 | buttons[BTN_GRID] = CWinButton(BTN_GRID, MENBAR, "Grid", CInputState::DISABLED, 73); 35 | buttons[BTN_SEP] = CWinButton(BTN_SEP, MENBAR, "Sep", CInputState::INACTIVE, 43); 36 | buttons[BTN_QCKLOOK] = CWinButton(BTN_QCKLOOK, MENBAR, "Qck Look", CInputState::DISABLED, 86); 37 | buttons[BTN_PSSR] = CWinButton(BTN_PSSR, MENBAR, "PSR_SYMBOL", CInputState::DISABLED, 40); 38 | buttons[BTN_EXT] = CWinButton(BTN_EXT, MENBAR, "Ext", CInputState::INACTIVE, 40); 39 | buttons[BTN_AUTOTAG] = CWinButton(BTN_AUTOTAG, MENBAR, "Auto Tag", CInputState::INACTIVE, 75); 40 | buttons[BTN_ALL] = CWinButton(BTN_ALL, MENBAR, "ALL", CInputState::DISABLED, 40); 41 | buttons[BTN_RTEDEL] = CWinButton(BTN_RTEDEL, MENBAR, "Rte Del", CInputState::INACTIVE, 75); 42 | 43 | // Text inputs 44 | textInputs[TXT_SEARCH] = CTextInput(TXT_SEARCH, MENBAR, "Search A/C: ", "", 100, CInputState::ACTIVE); 45 | 46 | /// Dropdown defaults 47 | map map; 48 | map.insert(make_pair("CZQX", false)); 49 | map.insert(make_pair("EGGX", false)); 50 | map.insert(make_pair("BDBX", false)); 51 | dropDowns[DRP_AREASEL] = CDropDown(DRP_AREASEL, MENBAR, "CZQX", &map, CInputState::INACTIVE, 83); 52 | map.clear(); 53 | dropDowns[DRP_TCKCTRL] = CDropDown(DRP_TCKCTRL, MENBAR, "None", &map, CInputState::INACTIVE, 88); 54 | map.clear(); 55 | map.insert(make_pair("ALL_TCKS", false)); 56 | map.insert(make_pair("TCKS_EAST", false)); 57 | map.insert(make_pair("TCKS_WEST", false)); 58 | map.insert(make_pair("TCKS_SEL", false)); 59 | dropDowns[DRP_OVERLAYS] = CDropDown(DRP_OVERLAYS, MENBAR, "ALL_TCKS", &map, CInputState::INACTIVE, 113); 60 | map.clear(); 61 | map.insert(make_pair("Delivery", false)); 62 | map.insert(make_pair("OCA Enroute", false)); 63 | map.insert(make_pair("Multi-role", false)); 64 | dropDowns[DRP_TYPESEL] = CDropDown(DRP_TYPESEL, MENBAR, "Multi-role", &map, CInputState::INACTIVE, 143); 65 | 66 | // Clogger 67 | CLogger::Log(CLogType::NORM, "Finished instantiation.", "MENUBAR"); 68 | } 69 | 70 | void CMenuBar::RenderBar(CDC* dc, Graphics* g, CRadarScreen* screen, string asel) { 71 | // Save context for later 72 | int sDC = dc->SaveDC(); 73 | 74 | // Brush to draw the bar 75 | CBrush brush(ScreenBlue.ToCOLORREF()); 76 | 77 | // Get screen width 78 | RECT radarArea = screen->GetRadarArea(); 79 | LONG screenWidth = radarArea.left + radarArea.right; 80 | 81 | // Create the base rectangle and the 3d bevel 82 | CRect baseMenuRectColour(radarArea.left, radarArea.top, radarArea.left + screenWidth, MENBAR_HEIGHT); 83 | dc->FillRect(baseMenuRectColour, &brush); 84 | CRect baseMenuRect(radarArea.left, radarArea.top, radarArea.left + screenWidth, MENBAR_HEIGHT); 85 | dc->Draw3dRect(baseMenuRect, ScreenBlue.ToCOLORREF(), BevelLight.ToCOLORREF()); 86 | 87 | // Draw the panels 88 | int menuOffsetX = 0; 89 | for (int i = 0; i <= sizeof(PANEL_SIZES) / sizeof(PANEL_SIZES[0]); i++) { 90 | CRect rect1(menuOffsetX, radarArea.top + 1, menuOffsetX + PANEL_SIZES[i], MENBAR_HEIGHT - 2); 91 | dc->Draw3dRect(rect1, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 92 | InflateRect(rect1, -1, -1); 93 | dc->Draw3dRect(rect1, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 94 | menuOffsetX += PANEL_SIZES[i] + 1; 95 | } 96 | 97 | /// ITEM RENDERING 98 | // Render zulu time 99 | FontSelector::SelectNormalFont(30, dc); 100 | dc->SetTextColor(TextWhite.ToCOLORREF()); 101 | dc->TextOutA(screen->GetRadarArea().right / 2, MENBAR_HEIGHT + 5, CUtils::ParseZuluTime(true).c_str()); 102 | 103 | // Font selection 104 | FontSelector::SelectNormalFont(MEN_FONT_SIZE, dc); 105 | dc->SetTextColor(TextWhite.ToCOLORREF()); 106 | dc->SetTextAlign(TA_CENTER); 107 | 108 | // Calculate date 109 | time_t now = time(0); 110 | tm* date = gmtime(&now); 111 | string strDate; 112 | strDate += to_string(date->tm_mon + 1); 113 | strDate += "-"; 114 | strDate += to_string(date->tm_mday); 115 | strDate += "-"; 116 | strDate += to_string(1900 + date->tm_year); 117 | 118 | // Render date 119 | dc->TextOutA(radarArea.left + 64, radarArea.top + 12.5, strDate.c_str()); 120 | 121 | // Buttons 122 | int idx = 0; 123 | int offsetX = 128; 124 | int offsetY = 30; 125 | string text = ""; 126 | for (auto kv : buttons) { 127 | // Offsets 128 | bool offsetIsItemSize = false; 129 | switch (kv.first) { 130 | case BTN_MISC: 131 | offsetX = 10; 132 | offsetY += MENBAR_BTN_HEIGHT + 1; 133 | offsetIsItemSize = true; 134 | break; 135 | case BTN_AREASEL: 136 | offsetX = RECT1_WIDTH + 10; 137 | offsetY = 30; 138 | offsetIsItemSize = true; 139 | break; 140 | case BTN_TCKCTRL: 141 | offsetIsItemSize = false; 142 | break; 143 | case BTN_RINGS: 144 | offsetIsItemSize = true; 145 | break; 146 | case BTN_OVERLAYS: 147 | offsetX += 164; 148 | break; 149 | case BTN_TYPESEL: 150 | offsetX = offsetX = RECT1_WIDTH + RECT2_WIDTH + 85; 151 | break; 152 | case BTN_ALTFILT: 153 | offsetX = RECT1_WIDTH + RECT2_WIDTH + RECT3_WIDTH + 10; 154 | break; 155 | case BTN_HALO: 156 | offsetX = RECT1_WIDTH + RECT2_WIDTH + RECT3_WIDTH + RECT4_WIDTH + 11; 157 | offsetY = 30; 158 | offsetIsItemSize = true; 159 | break; 160 | case BTN_PTL: 161 | offsetX = RECT1_WIDTH + RECT2_WIDTH + RECT3_WIDTH + RECT4_WIDTH + 11; 162 | offsetY += MENBAR_BTN_HEIGHT + 1; 163 | offsetIsItemSize = true; 164 | break; 165 | case BTN_QCKLOOK: 166 | offsetX = RECT1_WIDTH + RECT2_WIDTH + RECT3_WIDTH + RECT4_WIDTH + RECT5_WIDTH + 11; 167 | break; 168 | case BTN_PSSR: 169 | offsetX = RECT1_WIDTH + RECT2_WIDTH + RECT3_WIDTH + RECT4_WIDTH + RECT5_WIDTH + RECT6_WIDTH + RECT7_WIDTH + 35; 170 | offsetY = 30; 171 | offsetIsItemSize = true; 172 | break; 173 | case BTN_ALL: 174 | offsetX = RECT1_WIDTH + RECT2_WIDTH + RECT3_WIDTH + RECT4_WIDTH + RECT5_WIDTH + RECT6_WIDTH + RECT7_WIDTH + 35; 175 | offsetY += MENBAR_BTN_HEIGHT + 1; 176 | break; 177 | case BTN_RTEDEL: 178 | offsetX += 82; 179 | offsetIsItemSize = true; 180 | break; 181 | default: 182 | offsetIsItemSize = true; 183 | break; 184 | } 185 | 186 | // Button rendering 187 | if (kv.first != BTN_AREASEL && kv.first != BTN_TYPESEL && kv.first != BTN_RINGS) 188 | CCommonRenders::RenderButton(dc, screen, { offsetX, offsetY }, kv.second.Width, 30, &kv.second); 189 | 190 | // Text alignment 191 | dc->SetTextAlign(TA_LEFT); 192 | 193 | // Text rendering 194 | if (kv.first == BTN_DETAILED) { 195 | text = "Selected: " + (asel == "" ? "None" : asel); 196 | dc->TextOutA(offsetX + kv.second.Width + 4, offsetY + 7, text.c_str()); 197 | } 198 | else if (kv.first == BTN_OVERLAYS) { 199 | text = "Map"; 200 | dc->TextOutA(offsetX - (kv.second.Width / 2) - 2, offsetY + 7, text.c_str()); 201 | } 202 | else if (kv.first == BTN_TYPESEL) { 203 | text = "Pos Type"; 204 | dc->TextOutA(offsetX - kv.second.Width - 2, offsetY + 7, text.c_str()); 205 | } 206 | else if (kv.first == BTN_AREASEL) { 207 | dc->SetTextAlign(TA_CENTER); 208 | text = "Area Sel"; 209 | dc->TextOutA(offsetX + (kv.second.Width / 2), offsetY + 7, text.c_str()); 210 | } 211 | 212 | // If offsetting between buttons 213 | if (offsetIsItemSize) { 214 | offsetX += kv.second.Width + 1; 215 | } 216 | 217 | // Increment 218 | idx++; 219 | } 220 | 221 | // Misc items 222 | offsetX = RECT1_WIDTH + 10; 223 | offsetY += 8; 224 | for (auto kv : dropDowns) { 225 | // Offsets 226 | bool offsetIsItemSize = true; 227 | switch (kv.first) { 228 | case DRP_OVERLAYS: 229 | offsetX += 36; 230 | offsetIsItemSize = false; 231 | break; 232 | case DRP_TYPESEL: 233 | offsetX = RECT1_WIDTH + RECT2_WIDTH + 10; 234 | offsetIsItemSize = false; 235 | break; 236 | case DRP_AREASEL: 237 | offsetX = RECT1_WIDTH + 10; 238 | break; 239 | } 240 | 241 | // Render 242 | CCommonRenders::RenderDropDown(dc, g, screen, { offsetX, offsetY }, kv.second.Width, 20, &kv.second); 243 | 244 | // If offsetting between buttons 245 | if (offsetIsItemSize) { 246 | offsetX += kv.second.Width + 1; 247 | } 248 | } 249 | 250 | // Altitude filter (we only need this once so we draw it directly here) 251 | CRect altFilt(RECT1_WIDTH + RECT2_WIDTH + RECT3_WIDTH + 10, 61, RECT1_WIDTH + RECT2_WIDTH + RECT3_WIDTH + 10 + 86, 91); 252 | dc->FillSolidRect(altFilt, ButtonPressed.ToCOLORREF()); 253 | // Button bevel 254 | dc->Draw3dRect(altFilt, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 255 | InflateRect(altFilt, -1, -1); 256 | dc->Draw3dRect(altFilt, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 257 | 258 | /// Add screen objects for text 259 | // Low 260 | CSize rectSize = dc->GetTextExtent("000"); 261 | CRect lowRect(altFilt.left + 14, altFilt.top + 6, altFilt.left + 16 + rectSize.cx, altFilt.top + 6 + rectSize.cy); 262 | screen->AddScreenObject(ALTFILT_TEXT, "ALTFILT_LOW", lowRect, false, ""); 263 | // High 264 | CRect highRect(altFilt.right - 16 - rectSize.cx, altFilt.top + 6, altFilt.right - 14, altFilt.top + 6 + rectSize.cy); 265 | screen->AddScreenObject(ALTFILT_TEXT, "ALTFILT_HIGH", highRect, false, ""); 266 | 267 | // Text out 268 | string lowAlt = CUtils::PadWithZeros(3, CUtils::AltFiltLow); 269 | string highAlt = CUtils::PadWithZeros(3, CUtils::AltFiltHigh); 270 | dc->SetTextAlign(TA_CENTER); 271 | dc->TextOutA(altFilt.left + (altFilt.Width() / 2), altFilt.top + 7, (lowAlt + "-" + highAlt).c_str()); 272 | 273 | // Render the selection input 274 | dc->SetTextAlign(TA_LEFT); 275 | offsetX = RECT1_WIDTH + RECT2_WIDTH + RECT3_WIDTH + RECT4_WIDTH + RECT5_WIDTH + RECT6_WIDTH + 13; 276 | dc->TextOutA(offsetX, 30, textInputs[TXT_SEARCH].Label.c_str()); 277 | CCommonRenders::RenderTextInput(dc, screen, { offsetX, dc->GetTextExtent("ABCD").cy + 35 }, textInputs[TXT_SEARCH].Width, 20, & textInputs[TXT_SEARCH]); 278 | 279 | // Clean up 280 | DeleteObject(&brush); 281 | 282 | // Restore 283 | dc->RestoreDC(sDC); 284 | } 285 | 286 | bool CMenuBar::IsButtonPressed(int id) { 287 | // If button pressed 288 | if (id >= 100) { // dropdown 289 | if (dropDowns.find(id) != dropDowns.end() && dropDowns[id].State == CInputState::ACTIVE) return true; 290 | } 291 | else { 292 | if (buttons.find(id) != buttons.end() && buttons[id].State == CInputState::ACTIVE) return true; 293 | } 294 | 295 | return false; // Not pressed 296 | } 297 | 298 | string CMenuBar::GetDropDownValue(int id) { 299 | // Get the value 300 | return dropDowns[id].Value; 301 | } 302 | 303 | map CMenuBar::GetToggleButtons() { 304 | map map; 305 | map[BTN_PTL] = buttons[BTN_PTL]; 306 | map[BTN_RINGS] = buttons[BTN_RINGS]; 307 | map[BTN_HALO] = buttons[BTN_HALO]; 308 | 309 | return map; 310 | } 311 | 312 | void CMenuBar::MakeDropDownItems(int id) { 313 | if (id == DRP_TCKCTRL) { 314 | map map; 315 | for (auto kv : CRoutesHelper::CurrentTracks) { 316 | map.insert(make_pair(kv.first, true)); 317 | } 318 | dropDowns[DRP_TCKCTRL].Items.clear(); 319 | dropDowns[DRP_TCKCTRL].MakeItems(&map); 320 | } 321 | } 322 | 323 | void CMenuBar::SetButtonState(int id, CInputState state) { 324 | // Set the state to the requested one (with failsafe check) 325 | if (id >= 100) { // dropdown 326 | if (dropDowns.find(id)->second.State != CInputState::DISABLED) { 327 | if (dropDowns.find(id) != dropDowns.end()) { 328 | // Remove the old dropdown stuff 329 | if (ActiveDropDownHover != 0) { 330 | dropDowns[ActiveDropDown].Items[ActiveDropDownHover].IsHovered = false; 331 | ActiveDropDownHover = 0; 332 | } 333 | if (ActiveDropDown != 0) { 334 | dropDowns[ActiveDropDown].State = CInputState::INACTIVE; 335 | ActiveDropDown = 0; 336 | } 337 | 338 | dropDowns[id].State = state; 339 | ActiveDropDown = state == CInputState::ACTIVE ? id : 0; 340 | } 341 | } 342 | } 343 | else { // normal button 344 | if (buttons.find(id) != buttons.end()) { 345 | buttons[id].State = state; 346 | } 347 | } 348 | } 349 | 350 | void CMenuBar::SetTextInput(int id, string value) { 351 | if (textInputs.find(id) != textInputs.end()) { 352 | textInputs[id].Content = value; 353 | } 354 | } 355 | 356 | CInputState CMenuBar::GetButtonState(int id) { 357 | if (id >= 100) { // dropdown 358 | if (dropDowns.find(id) != dropDowns.end()) { 359 | return dropDowns.find(id)->second.State; 360 | } 361 | } 362 | else { 363 | if (buttons.find(id) != buttons.end()) { 364 | return buttons.find(id)->second.State; 365 | } 366 | } 367 | } 368 | 369 | void CMenuBar::OnOverDropDownItem(int id) { 370 | // Reset the hover state of the old one and set the state of new one 371 | if (ActiveDropDownHover != 0) { 372 | dropDowns[ActiveDropDown].Items[ActiveDropDownHover].IsHovered = false; 373 | dropDowns[ActiveDropDown].Items[id].IsHovered = true; 374 | } 375 | ActiveDropDownHover = id; 376 | } 377 | 378 | void CMenuBar::SetDropDownValue(int id, int value) { 379 | // Set the value 380 | dropDowns[id].Value = dropDowns[id].Items[value].Label; 381 | } 382 | 383 | void CMenuBar::ButtonDown(int id) { 384 | if (id == BTN_RTEDEL) 385 | SetButtonState(id, CInputState::ACTIVE); 386 | 387 | if (id == BTN_ADSC) 388 | SetButtonState(id, CInputState::ACTIVE); 389 | 390 | if (id == BTN_AUTOTAG) 391 | SetButtonState(id, CInputState::ACTIVE); 392 | } 393 | 394 | void CMenuBar::ButtonUp(int id) { 395 | if (id == BTN_RTEDEL) 396 | SetButtonState(id, CInputState::INACTIVE); 397 | 398 | if (id == BTN_ADSC) 399 | SetButtonState(id, CInputState::INACTIVE); 400 | 401 | if (id == BTN_AUTOTAG) 402 | SetButtonState(id, CInputState::INACTIVE); 403 | } 404 | 405 | void CMenuBar::ButtonPress(int id, int button, CRadarScreen* screen = nullptr) { 406 | if (button == EuroScopePlugIn::BUTTON_LEFT) { 407 | // Check if dropdown 408 | if (id >= 800) { 409 | if (!dropDowns[ActiveDropDown].Items[id].IsCheckItem) { 410 | // Set value 411 | dropDowns[ActiveDropDown].Value = dropDowns[ActiveDropDown].Items[id].Label; 412 | // Close drop down 413 | dropDowns[ActiveDropDown].Items[ActiveDropDownHover].IsHovered = false; 414 | ActiveDropDownHover = 0; 415 | dropDowns[ActiveDropDown].State = CInputState::INACTIVE; 416 | } else { 417 | dropDowns[ActiveDropDown].Items[ActiveDropDownHover].IsHovered = false; 418 | ActiveDropDownHover = 0; 419 | dropDowns[ActiveDropDown].Items[id].State = dropDowns[ActiveDropDown].Items[id].State == CInputState::INACTIVE ? CInputState::ACTIVE : CInputState::INACTIVE; 420 | } 421 | 422 | // Save values 423 | if (ActiveDropDown == DRP_AREASEL) { 424 | CUtils::AreaSelection = id; 425 | } else if (ActiveDropDown == DRP_OVERLAYS) { 426 | CUtils::SelectedOverlay = id; 427 | 428 | switch (id) { 429 | case 800: // ALL_TCKS 430 | COverlays::CurrentType = COverlayType::TCKS_ALL; 431 | break; 432 | case 801: // TCKS_EAST 433 | COverlays::CurrentType = COverlayType::TCKS_EAST; 434 | break; 435 | case 802: // TCKS_SEL 436 | COverlays::CurrentType = COverlayType::TCKS_SEL; 437 | break; 438 | case 803: // TCKS_WEST 439 | COverlays::CurrentType = COverlayType::TCKS_WEST; 440 | break; 441 | } 442 | } 443 | else if (ActiveDropDown == DRP_TYPESEL) { 444 | CUtils::PosType = id; 445 | } 446 | 447 | // Reset drop down 448 | if (!dropDowns[ActiveDropDown].Items[id].IsCheckItem) 449 | ActiveDropDown = 0; 450 | } 451 | else { 452 | // Press the button 453 | if (GetButtonState(id) != CInputState::DISABLED && id != BTN_RTEDEL) 454 | SetButtonState(id, CInputState::ACTIVE); 455 | 456 | // Grid 457 | if (id == BTN_GRID) { 458 | COverlays::ShowHideGridReference(screen, true); 459 | } 460 | } 461 | } 462 | else if (button == EuroScopePlugIn::BUTTON_RIGHT) { 463 | if (id == BTN_HALO) { 464 | // Get the toggle button 465 | auto haloBtn = buttons.find(BTN_HALO); 466 | 467 | // Increment if less than or equal 7 (100 mile halos max) 468 | if (haloBtn->second.Cycle < 7) { 469 | haloBtn->second.Cycle++; 470 | } 471 | else { 472 | haloBtn->second.Cycle = 0; 473 | } 474 | 475 | switch (haloBtn->second.Cycle) { 476 | case 0: 477 | haloBtn->second.Label = "Halo 5"; 478 | break; 479 | case 1: 480 | haloBtn->second.Label = "Halo 10"; 481 | break; 482 | case 2: 483 | haloBtn->second.Label = "Halo 15"; 484 | break; 485 | case 3: 486 | haloBtn->second.Label = "Halo 20"; 487 | break; 488 | case 4: 489 | haloBtn->second.Label = "Halo 25"; 490 | break; 491 | case 5: 492 | haloBtn->second.Label = "Halo 30"; 493 | break; 494 | case 6: 495 | haloBtn->second.Label = "Halo 60"; 496 | break; 497 | case 7: 498 | haloBtn->second.Label = "Halo 100"; 499 | break; 500 | } 501 | } 502 | 503 | if (id == BTN_PTL) { 504 | // Get the toggle button 505 | auto ptlBtn = buttons.find(BTN_PTL); 506 | 507 | // Increment if less than or equal 6 (60 minute lines max) 508 | if (ptlBtn->second.Cycle < 6) { 509 | ptlBtn->second.Cycle++; 510 | } 511 | else { 512 | ptlBtn->second.Cycle = 0; 513 | } 514 | switch (ptlBtn->second.Cycle) { 515 | case 0: 516 | ptlBtn->second.Label = "PTL 5"; 517 | break; 518 | case 1: 519 | ptlBtn->second.Label = "PTL 10"; 520 | break; 521 | case 2: 522 | ptlBtn->second.Label = "PTL 15"; 523 | break; 524 | case 3: 525 | ptlBtn->second.Label = "PTL 20"; 526 | break; 527 | case 4: 528 | ptlBtn->second.Label = "PTL 25"; 529 | break; 530 | case 5: 531 | ptlBtn->second.Label = "PTL 30"; 532 | break; 533 | case 6: 534 | ptlBtn->second.Label = "PTL 60"; 535 | break; 536 | } 537 | } 538 | 539 | if (id == BTN_RINGS) { 540 | // Get the toggle button 541 | auto ringsBtn = buttons.find(BTN_RINGS); 542 | 543 | // Increment if less than or equal 4 (5 rings max) 544 | if (ringsBtn->second.Cycle < 4) { 545 | ringsBtn->second.Cycle++; 546 | } 547 | else { 548 | ringsBtn->second.Cycle = 0; 549 | } 550 | 551 | switch (ringsBtn->second.Cycle) { 552 | case 0: 553 | ringsBtn->second.Label = "Rings 1"; 554 | break; 555 | case 1: 556 | ringsBtn->second.Label = "Rings 2"; 557 | break; 558 | case 2: 559 | ringsBtn->second.Label = "Rings 3"; 560 | break; 561 | case 3: 562 | ringsBtn->second.Label = "Rings 4"; 563 | break; 564 | case 4: 565 | ringsBtn->second.Label = "Rings 5"; 566 | break; 567 | } 568 | } 569 | } 570 | } 571 | 572 | void CMenuBar::ButtonUnpress(int id, int button, CRadarScreen* screen) { 573 | // Finally, unpress the button 574 | SetButtonState(id, CInputState::INACTIVE); 575 | 576 | // Grid 577 | if (id == BTN_GRID) { 578 | COverlays::ShowHideGridReference(screen, false); 579 | } 580 | 581 | // Flight data display 582 | if (id == BTN_ADSC) { 583 | // Open the FDD 584 | ShellExecute(NULL, "open", "https://vnaaats.net/fdd/", NULL, NULL, SW_SHOWNORMAL); 585 | } 586 | } 587 | 588 | void CMenuBar::GetSelectedTracks(vector& tracksVector) { 589 | for (auto idx : dropDowns[DRP_TCKCTRL].Items) { 590 | if (idx.second.State == CInputState::ACTIVE) { 591 | tracksVector.push_back(idx.second.Label); 592 | } 593 | } 594 | } -------------------------------------------------------------------------------- /VatsimNAAATS/CommonRenders.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "CommonRenders.h" 3 | #include "Styles.h" 4 | 5 | using namespace Colours; 6 | 7 | CRect CCommonRenders::RenderButton(CDC* dc, CRadarScreen* screen, POINT topLeft, int width, int height, CWinButton* obj, int vtcAlign) { 8 | // Save context for later 9 | int sDC = dc->SaveDC(); 10 | 11 | // Create rectangle 12 | CRect button(topLeft.x, topLeft.y, topLeft.x + width, topLeft.y + height); 13 | 14 | // Check if pressed 15 | if (obj->State == CInputState::ACTIVE) { 16 | dc->FillSolidRect(button, ButtonPressed.ToCOLORREF()); 17 | // Button bevel 18 | dc->Draw3dRect(button, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 19 | InflateRect(button, -1, -1); 20 | dc->Draw3dRect(button, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 21 | } 22 | else { 23 | dc->FillSolidRect(button, ScreenBlue.ToCOLORREF()); 24 | // Button bevel 25 | dc->Draw3dRect(button, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 26 | InflateRect(button, -1, -1); 27 | dc->Draw3dRect(button, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 28 | } 29 | 30 | // Draw text 31 | if (obj->Label == "PSR_SYMBOL") { 32 | FontSelector::SelectNormalFont(30, dc); 33 | obj->Label = "*"; 34 | } 35 | else { 36 | FontSelector::SelectNormalFont(16, dc); 37 | } 38 | 39 | if (obj->State == CInputState::DISABLED) { // Disabled text colour 40 | dc->SetTextColor(Disabled.ToCOLORREF()); 41 | } 42 | else { 43 | dc->SetTextColor(TextWhite.ToCOLORREF()); 44 | } 45 | dc->SetTextAlign(TA_CENTER); 46 | dc->TextOutA(button.left + (button.Width() / 2), button.top + (vtcAlign != -1 ? vtcAlign : ((button.bottom - button.top) / 4.5)), obj->Label.c_str()); 47 | 48 | // Restore device context 49 | dc->RestoreDC(sDC); 50 | 51 | // Add object and return the rectangle 52 | screen->AddScreenObject(obj->Type, to_string(obj->Id).c_str(), button, false, ""); 53 | 54 | // Return 55 | return button; 56 | } 57 | 58 | void CCommonRenders::RenderTextInput(CDC* dc, CRadarScreen* screen, POINT topLeft, int width, int height, CTextInput* obj) { 59 | // Save context for later 60 | int sDC = dc->SaveDC(); 61 | 62 | // Select font 63 | FontSelector::SelectATCFont(14, dc); 64 | dc->SetTextColor(TextWhite.ToCOLORREF()); 65 | dc->SetTextAlign(TA_LEFT); 66 | 67 | // Create rectangle 68 | CRect rect(topLeft.x, topLeft.y, topLeft.x + width, topLeft.y + height); 69 | 70 | // Draw rectangle 71 | dc->FillSolidRect(rect, ScreenBlue.ToCOLORREF()); 72 | // Button bevel 73 | dc->Draw3dRect(rect, BevelDark.ToCOLORREF(), BevelLight.ToCOLORREF()); 74 | InflateRect(rect, -1, -1); 75 | dc->Draw3dRect(rect, BevelDark.ToCOLORREF(), BevelLight.ToCOLORREF()); 76 | 77 | // Select text colour 78 | if (obj->State == CInputState::DISABLED) { 79 | dc->SetTextColor(Disabled.ToCOLORREF()); 80 | } 81 | else { 82 | dc->SetTextColor(TextWhite.ToCOLORREF()); 83 | } 84 | 85 | // Draw text 86 | dc->TextOutA(rect.left + 3, rect.top + 2, obj->Content.c_str()); 87 | 88 | // Restore device context 89 | dc->RestoreDC(sDC); 90 | 91 | // If editable, then add object and return the rectangle 92 | if (obj->State == CInputState::ACTIVE) { 93 | screen->AddScreenObject(obj->Type, to_string(obj->Id).c_str(), rect, false, ""); 94 | } 95 | } 96 | 97 | CRect CCommonRenders::RenderCheckBox(CDC* dc, Graphics* g, CRadarScreen* screen, POINT topLeft, int height, CCheckBox* obj) { 98 | // Save context for later 99 | int sDC = dc->SaveDC(); 100 | 101 | // Pens 102 | Pen white(TextWhite, 2); 103 | Pen grey(Grey, 2); 104 | 105 | // Create rectangle 106 | CRect rect(topLeft.x, topLeft.y, topLeft.x + height, topLeft.y + height); 107 | // Button bevel 108 | if (obj->IsChecked) { 109 | dc->Draw3dRect(rect, BevelDark.ToCOLORREF(), BevelLight.ToCOLORREF()); 110 | InflateRect(rect, -1, -1); 111 | dc->Draw3dRect(rect, BevelDark.ToCOLORREF(), BevelLight.ToCOLORREF()); 112 | dc->FillSolidRect(rect, ButtonPressed.ToCOLORREF()); 113 | g->DrawLine(&white, rect.left + 1, rect.top + 1, rect.right - 2, rect.bottom - 2); 114 | g->DrawLine(&white, rect.left + 1, rect.bottom - 2, rect.right - 2, rect.top + 1); 115 | } 116 | else { 117 | dc->Draw3dRect(rect, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 118 | InflateRect(rect, -1, -1); 119 | dc->Draw3dRect(rect, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 120 | } 121 | 122 | // Restore device context 123 | dc->RestoreDC(sDC); 124 | 125 | // Clean up 126 | DeleteObject(&white); 127 | DeleteObject(&grey); 128 | 129 | // Add object 130 | screen->AddScreenObject(obj->Type, to_string(obj->Id).c_str(), rect, false, ""); 131 | 132 | return rect; 133 | } 134 | 135 | void CCommonRenders::RenderDropDown(CDC* dc, Graphics* g, CRadarScreen* screen, POINT topLeft, int width, int height, CDropDown* obj) { 136 | // Save context for later 137 | int sDC = dc->SaveDC(); 138 | 139 | // Create dropdown area 140 | CRect dropDown(topLeft.x, topLeft.y, topLeft.x + width - 15, topLeft.y + height); 141 | 142 | // Pen 143 | Pen white(TextWhite, 2); 144 | 145 | // Fill 146 | dc->FillSolidRect(dropDown, ScreenBlue.ToCOLORREF()); 147 | 148 | // Select font 149 | FontSelector::SelectNormalFont(MEN_FONT_SIZE, dc); 150 | dc->SetTextColor(TextWhite.ToCOLORREF()); 151 | dc->SetTextAlign(TA_LEFT); 152 | 153 | // Dropdown bevel 154 | dc->Draw3dRect(dropDown, BevelDark.ToCOLORREF(), BevelLight.ToCOLORREF()); 155 | InflateRect(dropDown, -1, -1); 156 | dc->Draw3dRect(dropDown, BevelDark.ToCOLORREF(), BevelLight.ToCOLORREF()); 157 | 158 | // Create dropdown button 159 | CRect button(topLeft.x + width - 15, topLeft.y, topLeft.x + width, topLeft.y + height); 160 | 161 | // Value for main box 162 | string displayValue; 163 | 164 | // Check whether items are checked 165 | for (auto kv : obj->Items) { 166 | if (kv.second.IsCheckItem && kv.second.State == CInputState::ACTIVE) { 167 | displayValue += (displayValue.empty() && displayValue.size()) <= 3 ? kv.second.Label : (", " + kv.second.Label); 168 | displayValue += displayValue.size() > 3 ? "..." : ""; 169 | } 170 | 171 | } 172 | 173 | // Check if pressed 174 | if (obj->State == CInputState::ACTIVE) { 175 | // Draw text 176 | dc->FillSolidRect(button, ButtonPressed.ToCOLORREF()); 177 | CRect area(dropDown.left, dropDown.bottom, dropDown.right, dropDown.bottom + (obj->Items.size() * 20) + 2); 178 | dc->FillSolidRect(area, ScreenBlue.ToCOLORREF()); 179 | dc->Draw3dRect(area, BevelDark.ToCOLORREF(), BevelDark.ToCOLORREF()); 180 | 181 | // Draw text 182 | int offsetY = 2; 183 | int idx = 0; 184 | 185 | for (auto kv : obj->Items) { 186 | CRect object(area.left, area.top + offsetY, area.right, area.top + offsetY + 20); 187 | if (kv.second.IsHovered) 188 | dc->FillSolidRect(object, ButtonPressed.ToCOLORREF()); 189 | if (kv.second.IsCheckItem && kv.second.State == CInputState::ACTIVE) { 190 | CRect rect(object.right - 20, object.top, object.right, object.bottom); 191 | g->DrawLine(&white, rect.left + 4, rect.top + 4, rect.right - 4, rect.bottom - 4); 192 | g->DrawLine(&white, rect.left + 4, rect.bottom - 4, rect.right - 4, rect.top + 4); 193 | } 194 | dc->TextOutA(area.left + 2, area.top + offsetY + 2, kv.second.Label.c_str()); 195 | screen->AddScreenObject(kv.second.Type, to_string(kv.second.Id).c_str(), object, false, ""); 196 | offsetY += 20; 197 | idx; 198 | } 199 | } 200 | else { 201 | // Button 202 | dc->FillSolidRect(button, ScreenBlue.ToCOLORREF()); 203 | } 204 | 205 | // Write selected text 206 | obj->Value = !displayValue.empty() ? displayValue : obj->Value; 207 | if (obj->Id == 101 && obj->Type == MENBAR && displayValue.empty()) 208 | obj->Value = "None"; 209 | 210 | dc->TextOutA(dropDown.left + 2, dropDown.top + 1, obj->Value.c_str()); 211 | 212 | // Button triangle 213 | SolidBrush brush(Grey); 214 | g->SetSmoothingMode(SmoothingModeAntiAlias); 215 | // Coz GDI+ doesn't like GDI 216 | Rect rectangle(topLeft.x + width - 15, topLeft.y, topLeft.x + width, topLeft.y + height); 217 | Point points[3] = { Point(rectangle.X + 2, rectangle.Y + 4), 218 | Point(rectangle.X + 12, rectangle.Y + 4), 219 | Point(rectangle.X + 7, rectangle.Y + 14) }; 220 | g->FillPolygon(&brush, points, 3); 221 | // Button bevel 222 | dc->Draw3dRect(button, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 223 | InflateRect(button, -1, -1); 224 | dc->Draw3dRect(button, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 225 | 226 | // '3d' border trick 227 | Pen darkerPen(BevelDark, 1.5); 228 | g->DrawLine(&darkerPen, points[1], points[2]); 229 | 230 | // Restore device context 231 | dc->RestoreDC(sDC); 232 | 233 | // Clean up 234 | DeleteObject(&brush); 235 | DeleteObject(&darkerPen); 236 | DeleteObject(&white); 237 | 238 | // Add object 239 | screen->AddScreenObject(obj->Type, to_string(obj->Id).c_str(), button, false, ""); 240 | } 241 | 242 | void CCommonRenders::RenderScrollBar(CDC* dc, Graphics* g, CRadarScreen* screen, POINT topLeft, CWinScrollBar* scrollView) { 243 | // Save context for later 244 | int sDC = dc->SaveDC(); 245 | 246 | // Draw scroll track 247 | CRect scrollBarTrack; 248 | if (scrollView->IsHorizontal) { // Different track depending on whether it's horizontal or not 249 | scrollBarTrack = CRect(topLeft.x, topLeft.y, topLeft.x + scrollView->FrameSize, topLeft.y + 12); 250 | } 251 | else { 252 | scrollBarTrack = CRect(topLeft.x, topLeft.y, topLeft.x + 12, topLeft.y + scrollView->FrameSize); 253 | } 254 | dc->FillSolidRect(scrollBarTrack, ButtonPressed.ToCOLORREF()); 255 | dc->Draw3dRect(scrollBarTrack, BevelDark.ToCOLORREF(), BevelLight.ToCOLORREF()); 256 | InflateRect(scrollBarTrack, -1, -1); 257 | dc->Draw3dRect(scrollBarTrack, BevelDark.ToCOLORREF(), BevelLight.ToCOLORREF()); 258 | 259 | // Get grip position 260 | scrollView->PositionDelta = (scrollView->FrameSize - 12 - scrollView->GripSize) * (scrollView->WindowPos / scrollView->TotalScrollableArea); 261 | 262 | // Draw scroll buttons & grip 263 | CRect buttonRect1; 264 | CRect buttonRect2; 265 | CRect grip; 266 | SolidBrush brush(ScreenBlue); 267 | Pen lighterPen(BevelLight, 1.5); 268 | Pen darkerPen(BevelDark, 1.5); 269 | g->SetSmoothingMode(SmoothingModeAntiAlias); 270 | if (scrollView->IsHorizontal) { 271 | Point btnA[3] = { Point(scrollBarTrack.left + 1, scrollBarTrack.top + 4), 272 | Point(scrollBarTrack.left + 9, scrollBarTrack.top), 273 | Point(scrollBarTrack.left + 9, scrollBarTrack.bottom - 2) }; 274 | g->FillPolygon(&brush, btnA, 3); 275 | Point btnB[3] = { Point(scrollBarTrack.right - 2, scrollBarTrack.top + 4), 276 | Point(scrollBarTrack.right - 10, scrollBarTrack.top), 277 | Point(scrollBarTrack.right - 10, scrollBarTrack.bottom - 2) }; 278 | g->FillPolygon(&brush, btnB, 3); 279 | 280 | // Set rectangles 281 | buttonRect1 = CRect(scrollBarTrack.left, scrollBarTrack.top, scrollBarTrack.left + 11, scrollBarTrack.bottom); 282 | buttonRect2 = CRect(scrollBarTrack.right - 11, scrollBarTrack.top, scrollBarTrack.right, scrollBarTrack.bottom); 283 | 284 | // Grip 285 | grip = CRect(scrollBarTrack.left + 11 + (!isnan(scrollView->PositionDelta) ? scrollView->WindowPos : 0), scrollBarTrack.top, scrollBarTrack.left + (!isnan(scrollView->PositionDelta) ? scrollView->WindowPos : 0) + scrollView->GripSize, scrollBarTrack.bottom - 1); 286 | dc->FillSolidRect(grip, ScreenBlue.ToCOLORREF()); 287 | dc->Draw3dRect(grip, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 288 | InflateRect(grip, -1, -1); 289 | dc->Draw3dRect(grip, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 290 | 291 | // '3d' border trick 292 | g->DrawLine(&lighterPen, btnA[0], btnA[1]); 293 | g->DrawLine(&darkerPen, btnA[1], btnA[2]); 294 | g->DrawLine(&darkerPen, btnA[0], btnA[2]); 295 | g->DrawLine(&lighterPen, btnB[0], btnB[1]); 296 | g->DrawLine(&darkerPen, btnB[1], btnB[2]); 297 | g->DrawLine(&darkerPen, btnB[0], btnB[2]); 298 | } 299 | else { 300 | Point btnA[3] = { Point(scrollBarTrack.left + 3, scrollBarTrack.top + 1), 301 | Point(scrollBarTrack.left - 1, scrollBarTrack.top + 9), 302 | Point(scrollBarTrack.right - 2, scrollBarTrack.top + 9) }; 303 | g->FillPolygon(&brush, btnA, 3); 304 | Point btnB[3] = { Point(scrollBarTrack.left + 3, scrollBarTrack.bottom - 2), 305 | Point(scrollBarTrack.left - 1, scrollBarTrack.bottom - 10), 306 | Point(scrollBarTrack.right - 2, scrollBarTrack.bottom - 10) }; 307 | g->FillPolygon(&brush, btnB, 3); 308 | 309 | // Grip 310 | grip = CRect(scrollBarTrack.left, scrollBarTrack.top + 11 + (!isnan(scrollView->PositionDelta) ? scrollView->WindowPos : 0), scrollBarTrack.right - 1, scrollBarTrack.top + 11 + (!isnan(scrollView->PositionDelta) ? scrollView->WindowPos : 0) + scrollView->GripSize); 311 | dc->FillSolidRect(grip, ScreenBlue.ToCOLORREF()); 312 | dc->Draw3dRect(grip, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 313 | InflateRect(grip, -1, -1); 314 | dc->Draw3dRect(grip, BevelLight.ToCOLORREF(), BevelDark.ToCOLORREF()); 315 | 316 | // '3d' border trick 317 | g->DrawLine(&lighterPen, btnA[0], btnA[2]); 318 | g->DrawLine(&darkerPen, btnA[1], btnA[2]); 319 | g->DrawLine(&darkerPen, btnA[0], btnA[1]); 320 | g->DrawLine(&lighterPen, btnB[0], btnB[2]); 321 | g->DrawLine(&darkerPen, btnB[1], btnB[2]); 322 | g->DrawLine(&darkerPen, btnB[0], btnB[1]); 323 | } 324 | 325 | // Screen objects 326 | screen->AddScreenObject(scrollView->Type, to_string(scrollView->Id).c_str(), grip, true, ""); 327 | 328 | // Cleanup 329 | DeleteObject(&brush); 330 | DeleteObject(&lighterPen); 331 | DeleteObject(&darkerPen); 332 | 333 | // Restore device context 334 | dc->RestoreDC(sDC); 335 | } 336 | 337 | void CCommonRenders::RenderTracks(CDC* dc, Graphics* g, CRadarScreen* screen, COverlayType type, CMenuBar* menubar) { 338 | // Save context 339 | int iDC = dc->SaveDC(); 340 | 341 | // Pen 342 | Pen pen(TextWhite, 2); 343 | 344 | // Font 345 | FontSelector::SelectMonoFont(14, dc); 346 | dc->SetTextColor(TextWhite.ToCOLORREF()); 347 | dc->SetTextAlign(TA_CENTER); 348 | 349 | // Anti-aliasing 350 | g->SetSmoothingMode(SmoothingModeAntiAlias); 351 | 352 | // Loop tracks 353 | for (auto kv : CRoutesHelper::CurrentTracks) { 354 | // Show eastbound/eastbound only if that type is selected 355 | if (type == COverlayType::TCKS_EAST && kv.second.Direction != CTrackDirection::EAST) { 356 | continue; 357 | } 358 | else if (type == COverlayType::TCKS_WEST && kv.second.Direction != CTrackDirection::WEST) { 359 | continue; 360 | } 361 | 362 | // Show selected overlays 363 | if (type == COverlayType::TCKS_SEL) { 364 | vector tracks; 365 | menubar->GetSelectedTracks(tracks); 366 | bool show = false; 367 | for (int i = 0; i < tracks.size(); i++) { 368 | if (kv.first == tracks[i]) { 369 | show = true; 370 | } 371 | } 372 | if (!show) { 373 | continue; 374 | } 375 | } 376 | 377 | // Move to start and draw 378 | POINT pointCoord = screen->ConvertCoordFromPositionToPixel(kv.second.RouteRaw[0]); 379 | string id = kv.first; 380 | if (kv.second.Direction == CTrackDirection::EAST) { 381 | dc->TextOutA(pointCoord.x - 12, pointCoord.y - 5, id.c_str()); 382 | } 383 | else { 384 | dc->TextOutA(pointCoord.x + 12, pointCoord.y - 5, id.c_str()); 385 | } 386 | 387 | // Draw lines 388 | for (int i = 0; i < kv.second.RouteRaw.size(); i++) { 389 | g->DrawLine(&pen, pointCoord.x, pointCoord.y, screen->ConvertCoordFromPositionToPixel(kv.second.RouteRaw[i]).x, (screen->ConvertCoordFromPositionToPixel(kv.second.RouteRaw[i]).y)); 390 | pointCoord = screen->ConvertCoordFromPositionToPixel(kv.second.RouteRaw[i]); 391 | } 392 | } 393 | 394 | // Cleanup 395 | DeleteObject(&pen); 396 | 397 | // Restore context 398 | dc->RestoreDC(iDC); 399 | } 400 | 401 | void CCommonRenders::RenderRoutes(CDC* dc, Graphics* g, CRadarScreen* screen) { 402 | // Save context 403 | int iDC = dc->SaveDC(); 404 | 405 | // Pen & brush 406 | Pen pen(TargetOrange, 2); 407 | SolidBrush brush(TargetOrange); 408 | 409 | // Font 410 | FontSelector::SelectMonoFont(12, dc); 411 | dc->SetTextColor(TargetOrange.ToCOLORREF()); 412 | dc->SetTextAlign(TA_LEFT); 413 | 414 | // Anti-aliasing 415 | g->SetSmoothingMode(SmoothingModeAntiAlias); 416 | 417 | 418 | // Loop through each aircraft in the vector 419 | for (int i = 0; i < CRoutesHelper::ActiveRoutes.size(); i++) { 420 | // Get route 421 | vector route; 422 | CRoutesHelper::GetRoute(screen, &route, CRoutesHelper::ActiveRoutes.at(i)); 423 | 424 | // If route not there then we skip 425 | if (route.size() == route.empty()) { 426 | continue; 427 | } 428 | 429 | // Now we loop through each waypoint and draw the route 430 | POINT lastPoint = screen->ConvertCoordFromPositionToPixel(route.at(0).PositionRaw); 431 | for (int j = 0; j < route.size(); j++) { 432 | // Get point, text rectangle & define y offset 433 | string text = route.at(j).Fix; // To get TextExtent & check if AIRCRAFT 434 | 435 | // Only draw text if not aircraft position 436 | if (text != "AIRCRAFT") { 437 | POINT point = screen->ConvertCoordFromPositionToPixel(route.at(j).PositionRaw); 438 | CRect box(point.x - (dc->GetTextExtent(text.c_str()).cx / 2), point.y + 10, point.x + (dc->GetTextExtent(text.c_str()).cx), point.y + 50); 439 | int offsetY = 0; 440 | 441 | // Draw dot 442 | Rect pointRect(point.x - 3, point.y - 3, 6, 6); 443 | g->FillEllipse(&brush, pointRect); 444 | 445 | // Print text for fix 446 | dc->TextOutA(box.left, box.top, text.c_str()); 447 | offsetY += 14; 448 | 449 | // Print text for estimate 450 | text = route.at(j).Estimate; 451 | dc->TextOutA(box.left, box.top + offsetY, text.c_str()); 452 | offsetY += 14; 453 | 454 | // Print text for flight level 455 | text = to_string(route.at(j).FlightLevel); 456 | dc->TextOutA(box.left, box.top + offsetY, text.c_str()); 457 | } 458 | 459 | // Draw line to 460 | g->DrawLine(&pen, lastPoint.x, lastPoint.y, screen->ConvertCoordFromPositionToPixel(route.at(j).PositionRaw).x, (screen->ConvertCoordFromPositionToPixel(route.at(j).PositionRaw).y)); 461 | lastPoint = screen->ConvertCoordFromPositionToPixel(route.at(j).PositionRaw); 462 | } 463 | } 464 | 465 | // Cleanup 466 | DeleteObject(&pen); 467 | DeleteObject(&brush); 468 | 469 | // Restore context 470 | dc->RestoreDC(iDC); 471 | } 472 | 473 | void CCommonRenders::RenderQDM(CDC* dc, Graphics* g, CRadarScreen* screen, CPosition* position1, CPosition* position2, POINT cursorPosition, CPosition* cursorLatLon) { 474 | // Save context 475 | int iDC = dc->SaveDC(); 476 | 477 | // Get raw screen coordinates 478 | POINT rawPoint1(screen->ConvertCoordFromPositionToPixel(*position1)); 479 | POINT rawPoint2(screen->ConvertCoordFromPositionToPixel(*position2)); 480 | 481 | // Convert to Point objects 482 | Point point1(rawPoint1.x, rawPoint1.y); 483 | Point point2(rawPoint2.x, rawPoint2.y); 484 | 485 | // Drawing tools 486 | Pen pen(DarkGrey, 2); 487 | SolidBrush brush(DarkGrey); 488 | 489 | // Font 490 | FontSelector::SelectMonoFont(12, dc); 491 | dc->SetTextColor(TextWhite.ToCOLORREF()); 492 | dc->SetTextAlign(TA_CENTER); 493 | 494 | // Anti-aliasing 495 | g->SetSmoothingMode(SmoothingModeAntiAlias); 496 | 497 | // Define the positions 498 | Rect positionRect1(point1.X - 2, point1.Y - 2, 4, 4); 499 | Rect positionRect2(point2.X - 2, point2.Y - 2, 4, 4); 500 | 501 | // Fill number 1 502 | g->FillEllipse(&brush, positionRect1); 503 | 504 | // If number 2 defined fill it and draw line between, otherwise draw line to cursor position 505 | if (position2->m_Latitude != 0.0 && position2->m_Longitude != 0.0) { 506 | // Draw dots and connect 507 | g->FillEllipse(&brush, positionRect2); 508 | g->DrawLine(&pen, point1, point2); 509 | 510 | // Draw the lat lon text 511 | if (point1.Y < point2.Y) { 512 | // Point 1 has text on top 513 | dc->TextOutA(point1.X, point1.Y - 15, CUtils::GetLatLonString(position1, false, 2, false).c_str()); 514 | dc->TextOutA(point2.X, point2.Y + 10, CUtils::GetLatLonString(position2, false, 2, false).c_str()); 515 | } 516 | else { 517 | // Point 2 has text on top 518 | dc->TextOutA(point2.X, point2.Y - 15, CUtils::GetLatLonString(position2, false, 2, false).c_str()); 519 | dc->TextOutA(point1.X, point1.Y + 10, CUtils::GetLatLonString(position1, false, 2, false).c_str()); 520 | } 521 | 522 | // Draw distance text 523 | POINT midpoint = CUtils::GetMidPoint(rawPoint1, rawPoint2); 524 | dc->TextOutA(midpoint.x, midpoint.y, (to_string((int)position1->DistanceTo(*position2)) + "nm").c_str()); 525 | } 526 | else { 527 | g->DrawLine(&pen, point1, Point(cursorPosition.x, cursorPosition.y)); 528 | 529 | // Draw the lat lon text 530 | if (point1.Y < cursorPosition.y) { 531 | // Point 1 has text on top 532 | dc->TextOutA(point1.X, point1.Y - 15, CUtils::GetLatLonString(position1, false, 1, false).c_str()); 533 | dc->TextOutA(cursorPosition.x, cursorPosition.y + 10, CUtils::GetLatLonString(cursorLatLon, false, 2, false).c_str()); 534 | } 535 | else { 536 | // Point 2 has text on top 537 | dc->TextOutA(cursorPosition.x, cursorPosition.y - 15, CUtils::GetLatLonString(cursorLatLon, false, 2, false).c_str()); 538 | dc->TextOutA(point1.X, point1.Y + 10, CUtils::GetLatLonString(position1, false, 1, false).c_str()); 539 | } 540 | 541 | // Draw distance text 542 | POINT midpoint = CUtils::GetMidPoint(cursorPosition, rawPoint1); 543 | dc->TextOutA(midpoint.x, midpoint.y, (to_string((int)position1->DistanceTo(*cursorLatLon)) + "nm").c_str()); 544 | } 545 | 546 | // Cleanup 547 | DeleteObject(&pen); 548 | DeleteObject(&brush); 549 | 550 | // Restore context 551 | dc->RestoreDC(iDC); 552 | } --------------------------------------------------------------------------------