Skip to content

Commit

Permalink
feat: squawk assignment menu
Browse files Browse the repository at this point in the history
  • Loading branch information
AndyTWF committed Jun 3, 2023
1 parent 31d15af commit 43d02a2
Show file tree
Hide file tree
Showing 12 changed files with 275 additions and 43 deletions.
1 change: 1 addition & 0 deletions docs/TAG_FUNCTIONS.md
Expand Up @@ -22,3 +22,4 @@
9019 - Acknowledge Prenote Message
9020 - Trigger Missed Approach
9021 - Acknowledge Missed Approach
9022 - Open Squawk Assignment Menu
2 changes: 1 addition & 1 deletion src/plugin/squawk/SquawkAssignment.cpp
Expand Up @@ -45,7 +45,7 @@ namespace UKControllerPlugin::Squawk {
this->GeneralAssignmentNeeded(flightplan, radarTarget);
}

bool SquawkAssignment::AssignConspicuityAllowed(EuroScopeCFlightPlanInterface& flightplan) const
bool SquawkAssignment::DeleteApiSquawkAllowed(EuroScopeCFlightPlanInterface& flightplan) const
{
return this->activeCallsigns.UserHasCallsign() && (flightplan.IsTrackedByUser() || !flightplan.IsTracked());
}
Expand Down
3 changes: 1 addition & 2 deletions src/plugin/squawk/SquawkAssignment.h
Expand Up @@ -35,8 +35,7 @@ namespace UKControllerPlugin {
bool CircuitAssignmentNeeded(
UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan,
UKControllerPlugin::Euroscope::EuroScopeCRadarTargetInterface& radarTarget) const;
bool
AssignConspicuityAllowed(UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan) const;
bool DeleteApiSquawkAllowed(UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan) const;
bool ForceAssignmentAllowed(UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan) const;
bool ForceAssignmentNeeded(UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan) const;
bool ForceAssignmentOrNoSquawkAssigned(
Expand Down
92 changes: 92 additions & 0 deletions src/plugin/squawk/SquawkAssignmentMenu.cpp
@@ -0,0 +1,92 @@
#include "SquawkAssignmentMenu.h"
#include "SquawkGeneratorInterface.h"
#include "controller/ActiveCallsign.h"
#include "controller/ActiveCallsignCollection.h"
#include "euroscope/EuroScopeCFlightPlanInterface.h"
#include "euroscope/EuroscopePluginLoopbackInterface.h"
#include "euroscope/EuroscopeRadarLoopbackInterface.h"

namespace UKControllerPlugin::Squawk {

SquawkAssignmentMenu::SquawkAssignmentMenu(
int callbackId,
SquawkGeneratorInterface& squawkGenerator,
Controller::ActiveCallsignCollection& activeCallsigns,
Euroscope::EuroscopePluginLoopbackInterface& plugin)
: callbackId(callbackId), squawkGenerator(squawkGenerator), activeCallsigns(activeCallsigns), plugin(plugin)
{
}

void SquawkAssignmentMenu::DisplaySquawkAssignmentMenu(
Euroscope::EuroScopeCFlightPlanInterface& flightplan, const POINT& mousePos)
{
// If the user doesn't have a callsign or the callsign isn't active, don't show the menu
if (!this->activeCallsigns.UserHasCallsign()) {
return;
}

// Trigger the menu
plugin.TriggerPopupList(
{mousePos.x, mousePos.y, mousePos.x + MENU_WIDTH, mousePos.y + MENU_HEIGHT}, "Assign Squawk", 1);

// Add the options
this->AddMenuOptions();
}

void SquawkAssignmentMenu::AddMenuOptions()
{
Plugin::PopupMenuItem item;
item.firstValue = "";
item.secondValue = "";
item.callbackFunctionId = this->callbackId;
item.checked = EuroScopePlugIn::POPUP_ELEMENT_NO_CHECKBOX;
item.disabled = false;
item.fixedPosition = false;
this->plugin.AddItemToPopupList(item);

for (const auto& menuItem : this->squawkOptions) {
item.firstValue = menuItem;
this->plugin.AddItemToPopupList(item);
}
}

void SquawkAssignmentMenu::MenuOptionSelected(
Euroscope::EuroscopeRadarLoopbackInterface& radarScreen,
const std::string& option,
const POINT& mousePos,
const RECT& tagItemArea)
{
auto flightplan = this->plugin.GetSelectedFlightplan();
auto radarTarget = this->plugin.GetSelectedRadarTarget();
if (!flightplan || !radarTarget) {
LogWarning("No flightplan selected, cant action squawk menu selection");
return;
}

if (option == GENERAL_SQUAWK) {
this->squawkGenerator.ForceGeneralSquawkForAircraft(*flightplan, *radarTarget);
return;
}

if (option == LOCAL_SQUAWK) {
this->squawkGenerator.ForceLocalSquawkForAircraft(*flightplan, *radarTarget);
return;
}

if (option == CONSPICUITY) {
this->squawkGenerator.DeleteApiSquawkAndSetTo("7000", *flightplan);
return;
}

if (option == CIRCUIT) {
this->squawkGenerator.DeleteApiSquawkAndSetTo("7010", *flightplan);
return;
}

if (option == EUROSCOPE) {
radarScreen.ToggleEuroscopeTagFunction(
EuroScopePlugIn::TAG_ITEM_FUNCTION_SQUAWK_POPUP, flightplan->GetCallsign(), mousePos, tagItemArea);
return;
}
}
} // namespace UKControllerPlugin::Squawk
65 changes: 65 additions & 0 deletions src/plugin/squawk/SquawkAssignmentMenu.h
@@ -0,0 +1,65 @@
#pragma once

namespace UKControllerPlugin {
namespace Controller {
class ActiveCallsignCollection;
} // namespace Controller
namespace Euroscope {
class EuroscopePluginLoopbackInterface;
class EuroScopeCFlightPlanInterface;
class EuroscopeRadarLoopbackInterface;
} // namespace Euroscope
} // namespace UKControllerPlugin

namespace UKControllerPlugin::Squawk {

class SquawkGeneratorInterface;

/**
* A popup menu for choosing a squawk code to assign to a flight.
*/
class SquawkAssignmentMenu
{
public:
SquawkAssignmentMenu(
int callbackId,
SquawkGeneratorInterface& squawkGenerator,
Controller::ActiveCallsignCollection& activeCallsigns,
Euroscope::EuroscopePluginLoopbackInterface& plugin);
void DisplaySquawkAssignmentMenu(Euroscope::EuroScopeCFlightPlanInterface& flightplan, const POINT& mousePos);
void MenuOptionSelected(
Euroscope::EuroscopeRadarLoopbackInterface& radarScreen,
const std::string& option,
const POINT& mousePos,
const RECT& tagItemArea);

private:
void AddMenuOptions();

// Menu options
const char* GENERAL_SQUAWK = "General";
const char* LOCAL_SQUAWK = "Local";
const char* CONSPICUITY = "Conspicuity (7000)";
const char* CIRCUIT = "Circuit (7010)";
const char* EUROSCOPE = "Euroscope";

std::list<const char*> squawkOptions = {GENERAL_SQUAWK, LOCAL_SQUAWK, CONSPICUITY, CIRCUIT, EUROSCOPE};

// Menu sizes
static const int MENU_WIDTH = 200;
static const int MENU_HEIGHT = 200;

// The callback id to use for when a menu item is clicked
const int callbackId;

// The squawk generator
SquawkGeneratorInterface& squawkGenerator;

// Who's active as a controller
Controller::ActiveCallsignCollection& activeCallsigns;

// The plugin instance, lets us make menus
Euroscope::EuroscopePluginLoopbackInterface& plugin;
};

} // namespace UKControllerPlugin::Squawk
19 changes: 11 additions & 8 deletions src/plugin/squawk/SquawkGenerator.cpp
Expand Up @@ -60,23 +60,24 @@ namespace UKControllerPlugin::Squawk {
}

/**
* Removes the API squawk assignment and deletes the local
* Removes the API squawk assignment and changes the EuroScope callotion to the provided squawk.
*/
auto SquawkGenerator::AssignConspicuitySquawkForAircraft(EuroScopeCFlightPlanInterface& flightplan) -> bool
auto SquawkGenerator::DeleteApiSquawkAndSetTo(const std::string& squawk, EuroScopeCFlightPlanInterface& flightplan)
-> bool
{
if (!this->assignmentRules.AssignConspicuityAllowed(flightplan)) {
LogWarning("Cannot assign conspicuity squawk to " + flightplan.GetCallsign() + " - not allowed");
if (!this->assignmentRules.DeleteApiSquawkAllowed(flightplan)) {
LogWarning("Cannot delete api squawk " + flightplan.GetCallsign() + " - not allowed");
return false;
}

const auto currentSquawk = flightplan.GetAssignedSquawk();
if (!this->StartSquawkUpdate(flightplan)) {
if (!this->StartSquawkUpdate(flightplan, squawk)) {
return false;
}

const auto callsign = flightplan.GetCallsign();
if (storedFlightplans.HasFlightplanForCallsign(callsign)) {
storedFlightplans.GetFlightplanForCallsign(callsign).SetPreviouslyAssignedSquawk("7000");
storedFlightplans.GetFlightplanForCallsign(callsign).SetPreviouslyAssignedSquawk(squawk);
}

this->taskRunner->QueueAsynchronousTask([this, callsign, currentSquawk]() {
Expand Down Expand Up @@ -306,14 +307,16 @@ namespace UKControllerPlugin::Squawk {
/*
Places a request in progress to prevent duplicate requests
*/
auto SquawkGenerator::StartSquawkUpdate(EuroScopeCFlightPlanInterface& flightplan) -> bool
auto SquawkGenerator::StartSquawkUpdate(EuroScopeCFlightPlanInterface& flightplan, const std::string& processSquawk)
-> bool
{
// Lock the requests queue and mark the request as in progress. Set a holding squawk.
if (!this->squawkRequests.Start(flightplan.GetCallsign())) {
return false;
}

flightplan.SetSquawk(this->PROCESS_SQUAWK);
flightplan.SetSquawk(processSquawk);

return true;
}

Expand Down
21 changes: 11 additions & 10 deletions src/plugin/squawk/SquawkGenerator.h
@@ -1,5 +1,7 @@
#pragma once
#include "SquawkGeneratorInterface.h"
#include "SquawkRequest.h"
#include "squawk/SquawkGeneratorInterface.h"
#include "task/TaskRunnerInterface.h"

namespace UKControllerPlugin {
Expand Down Expand Up @@ -28,7 +30,7 @@ namespace UKControllerPlugin::Squawk {
/*
Makes the relevant API calls to generate a squawk for an aircraft.
*/
class SquawkGenerator
class SquawkGenerator : public SquawkGeneratorInterface
{
public:
SquawkGenerator(
Expand All @@ -38,18 +40,18 @@ namespace UKControllerPlugin::Squawk {
const UKControllerPlugin::Controller::ActiveCallsignCollection& callsigns,
const UKControllerPlugin::Flightplan::StoredFlightplanCollection& storedFlightplans,
const std::shared_ptr<UKControllerPlugin::Squawk::ApiSquawkAllocationHandler>& allocations);
auto
AssignConspicuitySquawkForAircraft(UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan)
-> bool;
auto AssignCircuitSquawkForAircraft(
UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan,
UKControllerPlugin::Euroscope::EuroScopeCRadarTargetInterface& radarTarget) const -> bool;
auto DeleteApiSquawkAndSetTo(
const std::string& squawk, UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan)
-> bool override;
auto ForceGeneralSquawkForAircraft(
UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan,
UKControllerPlugin::Euroscope::EuroScopeCRadarTargetInterface& radarTarget) -> bool;
UKControllerPlugin::Euroscope::EuroScopeCRadarTargetInterface& radarTarget) -> bool override;
auto ForceLocalSquawkForAircraft(
UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan,
UKControllerPlugin::Euroscope::EuroScopeCRadarTargetInterface& radarTarget) -> bool;
UKControllerPlugin::Euroscope::EuroScopeCRadarTargetInterface& radarTarget) -> bool override;
auto ReassignPreviousSquawkToAircraft(
UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan,
UKControllerPlugin::Euroscope::EuroScopeCRadarTargetInterface& radarTarget) const -> bool;
Expand All @@ -69,7 +71,9 @@ namespace UKControllerPlugin::Squawk {
CreateLocalSquawkAssignment(const std::string& callsign, std::string unit, std::string flightRules) const
-> bool;
void EndSquawkUpdate(std::string callsign);
auto StartSquawkUpdate(UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan) -> bool;
auto StartSquawkUpdate(
UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan,
const std::string& processSquawk = "7000") -> bool;

// Callsigns of logged in controllers
const UKControllerPlugin::Controller::ActiveCallsignCollection& activeCallsigns;
Expand All @@ -91,8 +95,5 @@ namespace UKControllerPlugin::Squawk {

// Receives API squawk allocations, so that they may be assigned to flightplans on the main thread
const std::shared_ptr<UKControllerPlugin::Squawk::ApiSquawkAllocationHandler> allocations;

// The squawk we set when a squawk is being generated
const std::string PROCESS_SQUAWK = "7000";
};
} // namespace UKControllerPlugin::Squawk
27 changes: 27 additions & 0 deletions src/plugin/squawk/SquawkGeneratorInterface.h
@@ -0,0 +1,27 @@
#pragma once

namespace UKControllerPlugin::Euroscope {
class EuroScopeCFlightPlanInterface;
class EuroScopeCRadarTargetInterface;
} // namespace UKControllerPlugin::Euroscope

namespace UKControllerPlugin::Squawk {

/*
Makes the relevant API calls to generate a squawk for an aircraft.
*/
class SquawkGeneratorInterface
{
public:
virtual ~SquawkGeneratorInterface() = default;
virtual auto DeleteApiSquawkAndSetTo(
const std::string& squawk, UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan)
-> bool = 0;
virtual auto ForceGeneralSquawkForAircraft(
UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan,
UKControllerPlugin::Euroscope::EuroScopeCRadarTargetInterface& radarTarget) -> bool = 0;
virtual auto ForceLocalSquawkForAircraft(
UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan,
UKControllerPlugin::Euroscope::EuroScopeCRadarTargetInterface& radarTarget) -> bool = 0;
};
} // namespace UKControllerPlugin::Squawk
31 changes: 31 additions & 0 deletions src/plugin/squawk/SquawkModule.cpp
Expand Up @@ -2,12 +2,15 @@
#include "ResetSquawkOnFailedDelete.h"
#include "SquawkAssignment.h"
#include "SquawkAssignmentDeleteForConspicuityFailedEvent.h"
#include "SquawkAssignmentMenu.h"
#include "SquawkEventHandler.h"
#include "SquawkGenerator.h"
#include "SquawkModule.h"
#include "bootstrap/PersistenceContainer.h"
#include "controller/ActiveCallsignCollection.h"
#include "controller/ControllerStatusEventHandlerCollection.h"
#include "euroscope/EuroscopeRadarLoopbackInterface.h"
#include "euroscope/RadarScreenCallbackFunction.h"
#include "euroscope/UserSettingAwareCollection.h"
#include "eventhandler/EventBus.h"
#include "eventhandler/EventHandlerFlags.h"
Expand Down Expand Up @@ -90,6 +93,34 @@ namespace UKControllerPlugin::Squawk {

container.pluginFunctionHandlers->RegisterFunctionCall(forceSquawkCallbackLocal);

// Squawk assignment menu
int squawkMenuCallbackId = container.pluginFunctionHandlers->ReserveNextDynamicFunctionId();
std::shared_ptr<SquawkAssignmentMenu> squawkMenu = std::make_shared<SquawkAssignmentMenu>(
squawkMenuCallbackId, *container.squawkGenerator, *container.activeCallsigns, *container.plugin);

// Register a callback function for when the option is selected
Euroscope::RadarScreenCallbackFunction menuCallbackFunction(
squawkMenuCallbackId,
"Squawk Assignment Menu Callback",
[squawkMenu](
int,
UKControllerPlugin::Euroscope::EuroscopeRadarLoopbackInterface& radarScreen,
const std::string& context,
const POINT& mousePos,
const RECT& area) { squawkMenu->MenuOptionSelected(radarScreen, context, mousePos, area); });
container.pluginFunctionHandlers->RegisterFunctionCall(menuCallbackFunction);

// Register the tag function
TagFunction squawkMenuTagFunction(
9022,
"Open Squawk Assignment Menu",
[squawkMenu](
UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& fp,
UKControllerPlugin::Euroscope::EuroScopeCRadarTargetInterface& rt,
const std::string& context,
const POINT& mousePos) { squawkMenu->DisplaySquawkAssignmentMenu(fp, mousePos); });
container.pluginFunctionHandlers->RegisterFunctionCall(squawkMenuTagFunction);

// Handler to reset squawks if delete fails
UKControllerPluginUtils::EventHandler::EventBus::Bus()
.AddHandler<SquawkAssignmentDeleteForConspicuityFailedEvent>(
Expand Down

0 comments on commit 43d02a2

Please sign in to comment.