Restore feature: clicking collapsed nav target clears target
- clicking on collapsed group of in-space bodies containing the nav target clears that target (no popup displayed) - PiGui.GetProjectedBodiesGrouped(): return additional info for each group; code cleanup / partial rewritemaster
parent
b1b64d0d6a
commit
e88d8476c2
|
@ -145,16 +145,15 @@ local function displayOnScreenObjects()
|
|||
local bodies_grouped = ui.getProjectedBodiesGrouped(collapse, IN_SPACE_INDICATOR_SHIP_MAX_DISTANCE)
|
||||
|
||||
for _,group in ipairs(bodies_grouped) do
|
||||
local mainBody = group[2].body
|
||||
local mainCoords = group[1].screenCoordinates
|
||||
local count = #group - 1
|
||||
local mainBody = group.mainBody
|
||||
local mainCoords = group.screenCoordinates
|
||||
|
||||
ui.addIcon(mainCoords, getBodyIcon(mainBody), colors.frame, iconsize, ui.anchor.center, ui.anchor.center)
|
||||
|
||||
if should_show_label then
|
||||
local label = mainBody:GetLabel()
|
||||
if count > 1 then
|
||||
label = label .. " (" .. count .. ")"
|
||||
if group.multiple then
|
||||
label = label .. " (" .. #group.bodies .. ")"
|
||||
end
|
||||
ui.addStyledText(mainCoords + Vector2(label_offset,0), ui.anchor.left, ui.anchor.center, label , colors.frame, pionillium.small)
|
||||
end
|
||||
|
@ -169,18 +168,17 @@ local function displayOnScreenObjects()
|
|||
-- mouse release handler
|
||||
if (mp - mainCoords):length() < click_radius then
|
||||
if not ui.isAnyWindowHovered() and ui.isMouseReleased(0) then
|
||||
if count == 1 then
|
||||
if navTarget == mainBody then
|
||||
-- if clicked and has nav target, unset nav target
|
||||
player:SetNavTarget(nil)
|
||||
navTarget = nil
|
||||
elseif combatTarget == mainBody then
|
||||
-- if clicked and has combat target, unset nav target
|
||||
player:SetCombatTarget(nil)
|
||||
combatTarget = nil
|
||||
else
|
||||
setTarget(mainBody)
|
||||
end
|
||||
if group.hasNavTarget then
|
||||
-- if clicked and has nav target, unset nav target
|
||||
player:SetNavTarget(nil)
|
||||
navTarget = nil
|
||||
elseif combatTarget == mainBody then
|
||||
-- if clicked and has combat target, unset nav target
|
||||
player:SetCombatTarget(nil)
|
||||
combatTarget = nil
|
||||
elseif not group.multiple then
|
||||
-- clicked on single, just set navtarget/combatTarget
|
||||
setTarget(mainBody)
|
||||
else
|
||||
-- clicked on group, show popup
|
||||
ui.openPopup("navtarget" .. mainBody:GetLabel())
|
||||
|
@ -190,35 +188,24 @@ local function displayOnScreenObjects()
|
|||
-- popup content
|
||||
ui.popup("navtarget" .. mainBody:GetLabel(), function()
|
||||
local small_iconsize = Vector2(16,16)
|
||||
ui.icon(getBodyIcon(mainBody), small_iconsize, colors.frame)
|
||||
ui.sameLine()
|
||||
if ui.selectable(mainBody:GetLabel(), mainBody == navTarget, {}) then
|
||||
if mainBody:IsShip() then
|
||||
player:SetCombatTarget(mainBody)
|
||||
else
|
||||
player:SetNavTarget(mainBody)
|
||||
for _,b in pairs(group.bodies) do
|
||||
ui.icon(getBodyIcon(b), small_iconsize, colors.frame)
|
||||
ui.sameLine()
|
||||
if ui.selectable(b:GetLabel(), b == navTarget, {}) then
|
||||
if b:IsShip() then
|
||||
player:SetCombatTarget(b)
|
||||
else
|
||||
player:SetNavTarget(b)
|
||||
end
|
||||
end
|
||||
if ui.ctrlHeld() then
|
||||
local target = mainBody
|
||||
local target = b
|
||||
if target == player:GetSetSpeedTarget() then
|
||||
target = nil
|
||||
end
|
||||
player:SetSetSpeedTarget(target)
|
||||
end
|
||||
end
|
||||
for _,v in pairs(group) do
|
||||
if v.body and v.body~=mainBody then
|
||||
ui.icon(getBodyIcon(v.body), small_iconsize, colors.frame)
|
||||
ui.sameLine()
|
||||
if ui.selectable(v.body:GetLabel(), v.body == navTarget, {}) then
|
||||
if v.body:IsShip() then
|
||||
player:SetCombatTarget(v.body)
|
||||
else
|
||||
player:SetNavTarget(v.body)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
141
src/LuaPiGui.cpp
141
src/LuaPiGui.cpp
|
@ -1467,9 +1467,9 @@ bool first_body_is_more_important_than(Body *body, Body *other)
|
|||
* Function: GetProjectedBodiesGrouped
|
||||
*
|
||||
* Returns all bodies visible on screen, grouped into clusters of bodies
|
||||
* that are close together on screen.
|
||||
* which are close together on screen.
|
||||
*
|
||||
* > GetProjectedBodiesGrouped(collapse, ship_max_distance)
|
||||
* > groups = Engine.pigui.GetProjectedBodiesGrouped(collapse, ship_max_distance)
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
|
@ -1477,6 +1477,18 @@ bool first_body_is_more_important_than(Body *body, Body *other)
|
|||
*
|
||||
* ship_max_distance - ships farther away than this are not included in the result
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* groups - array of info records describing each group
|
||||
*
|
||||
* Fields in info record:
|
||||
*
|
||||
* screenCoordinates - coordinates of the geometric centre of the group
|
||||
* mainBody - the main <Body> of the group
|
||||
* hasNavTarget - true if group contains the player's current navigation target
|
||||
* multiple - true if group consists of more than one body
|
||||
* bodies - array of all <Body> objects in the group, sorted by importance
|
||||
*
|
||||
* Availability:
|
||||
*
|
||||
* 2019-12
|
||||
|
@ -1505,78 +1517,79 @@ static int l_pigui_get_projected_bodies_grouped(lua_State *l)
|
|||
filtered.back()._body = body;
|
||||
}
|
||||
|
||||
std::vector<TSS_vector> groups;
|
||||
groups.reserve(filtered.size());
|
||||
struct GroupInfo {
|
||||
Body *m_mainBody;
|
||||
vector2d m_centreCoords; // screen space centre of group
|
||||
vector3d m_worldCoordSum; // coord sum of all bodies in group
|
||||
std::vector<Body *> m_bodies;
|
||||
bool m_hasNavTarget;
|
||||
|
||||
// Perform half-matrix double for
|
||||
for (TSS_vector::iterator it = filtered.begin(); it != filtered.end(); ++it) {
|
||||
TSS_vector group;
|
||||
group.reserve(filtered.end() - it + 1);
|
||||
|
||||
// First element should always be the "media";
|
||||
// so push twice that element:
|
||||
//printf(" Body 1 = %s (%f, %f)\n", (*it)._body->GetLabel().c_str(), (*it)._screenPosition.x, (*it)._screenPosition.y);
|
||||
group.push_back((*it));
|
||||
// Zeroed body so you could distinguish between a "media" element and a "real" element
|
||||
group.back()._body = nullptr;
|
||||
group.push_back((*it));
|
||||
|
||||
// Find near displayed bodies in remaining list of bodies
|
||||
for (TSS_vector::iterator it2 = --filtered.end(); it2 != it;) {
|
||||
//printf(" Body 2 = %s (%f, %f)\n", (*it2)._body->GetLabel().c_str(), (*it2)._screenPosition.x, (*it2)._screenPosition.y);
|
||||
if ((std::abs((*group.begin())._screenPosition.x - (*it2)._screenPosition.x) > gap.x) ||
|
||||
(std::abs((*group.begin())._screenPosition.y - (*it2)._screenPosition.y) > gap.y)) {
|
||||
it2--;
|
||||
continue;
|
||||
}
|
||||
//printf(" %s and %s are near!\n", (*it)._body->GetLabel().c_str(), (*it2)._body->GetLabel().c_str());
|
||||
// There's a "nearest": push it on group, remove from filtered and recalc group center
|
||||
group.push_back(*it2);
|
||||
// nearly-swap&pop: copy last element over *it2 and...
|
||||
(*it2) = filtered.back();
|
||||
// ensure it2 never point past-the-end (thus to rbegin)
|
||||
it2--;
|
||||
// ..."pop"
|
||||
filtered.pop_back();
|
||||
// recalc group (starting with second element because first is the center itself)
|
||||
vector3d media = std::accumulate(group.begin() + 1, group.end(), vector3d(0.0), [](const vector3d &a, const TScreenSpace &ss) {
|
||||
//printf(" Third level with '%s'\n", ss._body->GetLabel().c_str());
|
||||
return a + ss._body->GetPositionRelTo(Pi::player);
|
||||
});
|
||||
media /= double(group.size() - 1);
|
||||
group.front() = lua_world_space_to_screen_space(media);
|
||||
group.front()._body = nullptr; // <- just in case...
|
||||
GroupInfo(Body *b, const vector2d &coords, bool isNavTarget) :
|
||||
m_mainBody(b),
|
||||
m_centreCoords(coords),
|
||||
m_worldCoordSum(b->GetPositionRelTo(Pi::player)),
|
||||
m_hasNavTarget(isNavTarget)
|
||||
{
|
||||
m_bodies.push_back(b);
|
||||
}
|
||||
};
|
||||
std::vector<GroupInfo> groups;
|
||||
groups.reserve(filtered.size());
|
||||
const Body *nav_target = Pi::game->GetPlayer()->GetNavTarget();
|
||||
|
||||
for (TScreenSpace &obj : filtered) {
|
||||
bool inserted = false;
|
||||
for (GroupInfo &group : groups) {
|
||||
if ((std::abs(group.m_centreCoords.x - obj._screenPosition.x) <= gap.x) &&
|
||||
(std::abs(group.m_centreCoords.y - obj._screenPosition.y) <= gap.y)) {
|
||||
// body inside group boundaries: insert into group
|
||||
group.m_bodies.push_back(obj._body);
|
||||
if (obj._body == nav_target)
|
||||
group.m_hasNavTarget = true;
|
||||
|
||||
// recalc centre
|
||||
group.m_worldCoordSum += obj._body->GetPositionRelTo(Pi::player);
|
||||
vector3d centre = group.m_worldCoordSum / static_cast<double>(group.m_bodies.size());
|
||||
group.m_centreCoords = lua_world_space_to_screen_space(centre)._screenPosition;
|
||||
inserted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!inserted) {
|
||||
// create new group
|
||||
GroupInfo newgroup(obj._body, obj._screenPosition,
|
||||
obj._body == nav_target ? true : false);
|
||||
groups.push_back(std::move(newgroup));
|
||||
}
|
||||
groups.push_back(std::move(group));
|
||||
}
|
||||
|
||||
// Sort each groups member according to a given function (skipping first element)
|
||||
std::for_each(begin(groups), end(groups), [](TSS_vector &group) {
|
||||
std::sort(begin(group) + 1, end(group), [](TScreenSpace &a, TScreenSpace &b) {
|
||||
return first_body_is_more_important_than(a._body, b._body);
|
||||
});
|
||||
});
|
||||
// Sort each groups member according to a given function
|
||||
for (GroupInfo &group : groups) {
|
||||
std::sort(begin(group.m_bodies), end(group.m_bodies),
|
||||
[](Body *a, Body *b) {
|
||||
return first_body_is_more_important_than(a, b);
|
||||
});
|
||||
// make most important body the main body
|
||||
group.m_mainBody = group.m_bodies.front();
|
||||
}
|
||||
|
||||
LuaTable result(l, groups.size(), 0);
|
||||
int index = 1;
|
||||
|
||||
std::for_each(begin(groups), end(groups), [&l, &result, &index](TSS_vector &group) {
|
||||
int index2 = 1;
|
||||
LuaTable table_group(l, group.size(), 0);
|
||||
for (GroupInfo &group : groups) {
|
||||
LuaTable info_table(l, 0, 5);
|
||||
LuaTable bodies_table(l, group.m_bodies.size(), 0);
|
||||
|
||||
std::for_each(begin(group), end(group), [&l, &table_group, &index2](TScreenSpace &on_screen_object) {
|
||||
LuaTable object(l, 0, 3);
|
||||
object.Set("onscreen", on_screen_object._onScreen);
|
||||
object.Set("screenCoordinates", on_screen_object._screenPosition);
|
||||
if (on_screen_object._body != nullptr)
|
||||
object.Set("body", on_screen_object._body);
|
||||
|
||||
table_group.Set(index2++, object);
|
||||
lua_pop(l, 1);
|
||||
});
|
||||
result.Set(index++, table_group);
|
||||
info_table.Set("screenCoordinates", group.m_centreCoords);
|
||||
info_table.Set("mainBody", group.m_mainBody);
|
||||
bodies_table.LoadVector(group.m_bodies.begin(), group.m_bodies.end());
|
||||
info_table.Set("bodies", bodies_table);
|
||||
lua_pop(l, 1);
|
||||
});
|
||||
info_table.Set("multiple", group.m_bodies.size() > 1 ? true : false);
|
||||
info_table.Set("hasNavTarget", group.m_hasNavTarget);
|
||||
result.Set(index++, info_table);
|
||||
lua_pop(l, 1);
|
||||
}
|
||||
LuaPush(l, result);
|
||||
return 1;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue