# Add double-click and triple-click selection modes, based on patch by Christoph and evans.
Fixes #515. This was SVN commit r8544.
This commit is contained in:
parent
f45c74c368
commit
644b9aedea
@ -37,9 +37,18 @@ specialKeyStates[SDLK_RCTRL] = 0;
|
||||
specialKeyStates[SDLK_LCTRL] = 0;
|
||||
specialKeyStates[SDLK_RALT] = 0;
|
||||
specialKeyStates[SDLK_LALT] = 0;
|
||||
|
||||
// (TODO: maybe we should fix the hotkey system to be usable in this situation,
|
||||
// rather than hardcoding Shift into this code?)
|
||||
// rather than hardcoding Shift/Ctrl/Alt into this code?)
|
||||
|
||||
// Number of pixels the mouse can move before the action is considered a drag
|
||||
var maxDragDelta = 4;
|
||||
|
||||
// Time in milliseconds in which a double click is recognized
|
||||
const doubleClickTime = 500;
|
||||
var doubleClickTimer = 0;
|
||||
var doubleClicked = false;
|
||||
// Store the previously clicked entity - ensure a double/triple click happens on the same entity
|
||||
var prevClickedEntity = 0;
|
||||
|
||||
function updateCursor()
|
||||
{
|
||||
@ -125,7 +134,6 @@ function determineAction(x, y, fromMinimap)
|
||||
var playerOwned = ((targetState.player == entState.player)? true : false);
|
||||
var enemyOwned = ((targetState.player != entState.player)? true : false);
|
||||
var gaiaOwned = ((targetState.player == 0)? true : false);
|
||||
|
||||
|
||||
if (targetState.garrisonHolder && playerOwned && ctrlPressed)
|
||||
{
|
||||
@ -571,7 +579,7 @@ function handleInputAfterGui(ev)
|
||||
// If the mouse moved further than a limit, switch to bandbox mode
|
||||
var dragDeltaX = ev.x - dragStart[0];
|
||||
var dragDeltaY = ev.y - dragStart[1];
|
||||
var maxDragDelta = 4;
|
||||
|
||||
if (Math.abs(dragDeltaX) >= maxDragDelta || Math.abs(dragDeltaY) >= maxDragDelta)
|
||||
{
|
||||
inputState = INPUT_BANDBOXING;
|
||||
@ -593,12 +601,51 @@ function handleInputAfterGui(ev)
|
||||
return true;
|
||||
}
|
||||
|
||||
var onScreenOnly;
|
||||
var selectedEntity = ents[0];
|
||||
var now = new Date();
|
||||
|
||||
if ((now.getTime() - doubleClickTimer < doubleClickTime) && (selectedEntity == prevClickedEntity))
|
||||
{
|
||||
// Double click or triple click has occurred
|
||||
|
||||
// Check for double click or triple click
|
||||
if (!doubleClicked)
|
||||
{
|
||||
// If double click hasn't already occurred, this is a double click.
|
||||
// Select only similar on-screen units
|
||||
onScreenOnly = true;
|
||||
doubleClicked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Double click has already occurred, so this is a triple click.
|
||||
// Select all similar units whether they are on-screen or not
|
||||
onScreenOnly = false;
|
||||
}
|
||||
|
||||
var templateToMatch = Engine.GuiInterfaceCall("GetEntityState", selectedEntity).template;
|
||||
|
||||
ents = Engine.PickSimilarFriendlyEntities(templateToMatch, onScreenOnly);
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's single click right now but it may become double or triple click
|
||||
doubleClicked = false;
|
||||
doubleClickTimer = now.getTime();
|
||||
prevClickedEntity = selectedEntity;
|
||||
|
||||
// We only want to include the first picked unit in the selection
|
||||
ents = [ents[0]];
|
||||
}
|
||||
|
||||
// If shift is pressed, don't reset the selection, but allow units to be added to the existing selection
|
||||
var addition = (specialKeyStates[SDLK_RSHIFT] || specialKeyStates[SDLK_LSHIFT]);
|
||||
if (!addition)
|
||||
g_Selection.reset();
|
||||
g_Selection.reset();
|
||||
|
||||
g_Selection.addList([ents[0]]);
|
||||
g_Selection.addList(ents);
|
||||
|
||||
inputState = INPUT_NORMAL;
|
||||
return true;
|
||||
}
|
||||
|
@ -128,6 +128,11 @@ std::vector<entity_id_t> PickFriendlyEntitiesInRect(void* UNUSED(cbdata), int x0
|
||||
return EntitySelection::PickEntitiesInRect(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x0, y0, x1, y1, player);
|
||||
}
|
||||
|
||||
std::vector<entity_id_t> PickSimilarFriendlyEntities(void* UNUSED(cbdata), std::string templateName, bool onScreenOnly)
|
||||
{
|
||||
return EntitySelection::PickSimilarEntities(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), templateName, g_Game->GetPlayerID(), onScreenOnly);
|
||||
}
|
||||
|
||||
CFixedVector3D GetTerrainAtPoint(void* UNUSED(cbdata), int x, int y)
|
||||
{
|
||||
CVector3D pos = g_Game->GetView()->GetCamera()->GetWorldCoordinates(x, y, true);
|
||||
@ -374,6 +379,7 @@ void GuiScriptingInit(ScriptInterface& scriptInterface)
|
||||
// Entity picking
|
||||
scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, int, &PickEntitiesAtPoint>("PickEntitiesAtPoint");
|
||||
scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, int, int, int, int, &PickFriendlyEntitiesInRect>("PickFriendlyEntitiesInRect");
|
||||
scriptInterface.RegisterFunction<std::vector<entity_id_t>, std::string, bool, &PickSimilarFriendlyEntities>("PickSimilarFriendlyEntities");
|
||||
scriptInterface.RegisterFunction<CFixedVector3D, int, int, &GetTerrainAtPoint>("GetTerrainAtPoint");
|
||||
|
||||
// Network / game setup functions
|
||||
|
@ -131,6 +131,8 @@ public:
|
||||
|
||||
virtual std::vector<std::wstring> FindAllTemplates();
|
||||
|
||||
virtual std::vector<entity_id_t> GetEntitiesUsingTemplate(std::string templateName);
|
||||
|
||||
private:
|
||||
// Entity template XML validator
|
||||
RelaxNGValidator m_Validator;
|
||||
@ -405,6 +407,20 @@ std::vector<std::wstring> CCmpTemplateManager::FindAllTemplates()
|
||||
return templates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of entities using the specified template
|
||||
*/
|
||||
std::vector<entity_id_t> CCmpTemplateManager::GetEntitiesUsingTemplate(std::string templateName)
|
||||
{
|
||||
std::vector<entity_id_t> entities;
|
||||
for (std::map<entity_id_t, std::string>::const_iterator it = m_LatestTemplates.begin(); it != m_LatestTemplates.end(); ++it)
|
||||
{
|
||||
if(it->second == templateName)
|
||||
entities.push_back(it->first);
|
||||
}
|
||||
return entities;
|
||||
}
|
||||
|
||||
void CCmpTemplateManager::CopyPreviewSubset(CParamNode& out, const CParamNode& in, bool corpse)
|
||||
{
|
||||
// We only want to include components which are necessary (for the visual previewing of an entity)
|
||||
|
@ -25,4 +25,5 @@ BEGIN_INTERFACE_WRAPPER(TemplateManager)
|
||||
DEFINE_INTERFACE_METHOD_1("GetTemplate", const CParamNode*, ICmpTemplateManager, GetTemplate, std::string)
|
||||
DEFINE_INTERFACE_METHOD_1("GetCurrentTemplateName", std::string, ICmpTemplateManager, GetCurrentTemplateName, entity_id_t)
|
||||
DEFINE_INTERFACE_METHOD_0("FindAllTemplates", std::vector<std::wstring>, ICmpTemplateManager, FindAllTemplates)
|
||||
DEFINE_INTERFACE_METHOD_1("GetEntitiesUsingTemplate", std::vector<entity_id_t>, ICmpTemplateManager, GetEntitiesUsingTemplate, std::string)
|
||||
END_INTERFACE_WRAPPER(TemplateManager)
|
||||
|
@ -79,6 +79,11 @@ public:
|
||||
*/
|
||||
virtual std::string GetCurrentTemplateName(entity_id_t ent) = 0;
|
||||
|
||||
/**
|
||||
* Returns the list of entities having the specified template.
|
||||
*/
|
||||
virtual std::vector<entity_id_t> GetEntitiesUsingTemplate(std::string templateName) = 0;
|
||||
|
||||
/**
|
||||
* Returns a list of strings that could be validly passed as @c templateName to LoadTemplate.
|
||||
* (This includes "actor|foo" etc names).
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "simulation2/Simulation2.h"
|
||||
#include "simulation2/components/ICmpOwnership.h"
|
||||
#include "simulation2/components/ICmpRangeManager.h"
|
||||
#include "simulation2/components/ICmpTemplateManager.h"
|
||||
#include "simulation2/components/ICmpSelectable.h"
|
||||
#include "simulation2/components/ICmpVisual.h"
|
||||
|
||||
@ -130,3 +131,44 @@ std::vector<entity_id_t> EntitySelection::PickEntitiesInRect(CSimulation2& simul
|
||||
|
||||
return hitEnts;
|
||||
}
|
||||
|
||||
std::vector<entity_id_t> EntitySelection::PickSimilarEntities(CSimulation2& simulation, const CCamera& camera, std::string templateName, int owner, bool onScreenOnly)
|
||||
{
|
||||
CmpPtr<ICmpTemplateManager> cmpTemplateManager(simulation, SYSTEM_ENTITY);
|
||||
CmpPtr<ICmpRangeManager> cmpRangeManager(simulation, SYSTEM_ENTITY);
|
||||
|
||||
std::vector<entity_id_t> hitEnts;
|
||||
|
||||
std::vector<entity_id_t> entities = cmpTemplateManager->GetEntitiesUsingTemplate(templateName);
|
||||
for (std::vector<entity_id_t>::iterator it = entities.begin(); it != entities.end(); ++it)
|
||||
{
|
||||
entity_id_t ent = *it;
|
||||
|
||||
// Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
|
||||
// In this case, the checking is done to avoid selecting garrisoned units
|
||||
if (cmpRangeManager->GetLosVisibility(ent, owner) == ICmpRangeManager::VIS_HIDDEN)
|
||||
continue;
|
||||
|
||||
// Ignore entities not owned by 'owner'
|
||||
CmpPtr<ICmpOwnership> cmpOwnership(simulation.GetSimContext(), ent);
|
||||
if (cmpOwnership.null() || cmpOwnership->GetOwner() != owner)
|
||||
continue;
|
||||
|
||||
if (onScreenOnly)
|
||||
{
|
||||
// Find the current interpolated model position.
|
||||
CmpPtr<ICmpVisual> cmpVisual(simulation.GetSimContext(), ent);
|
||||
if (cmpVisual.null())
|
||||
continue;
|
||||
CVector3D position = cmpVisual->GetPosition();
|
||||
|
||||
// Reject if it's not on-screen (e.g. it's behind the camera)
|
||||
if (!camera.GetFrustum().IsPointVisible(position))
|
||||
continue;
|
||||
}
|
||||
|
||||
hitEnts.push_back(ent);
|
||||
}
|
||||
|
||||
return hitEnts;
|
||||
}
|
||||
|
@ -47,6 +47,13 @@ std::vector<entity_id_t> PickEntitiesAtPoint(CSimulation2& simulation, const CCa
|
||||
*/
|
||||
std::vector<entity_id_t> PickEntitiesInRect(CSimulation2& simulation, const CCamera& camera, int sx0, int sy0, int sx1, int sy1, int owner);
|
||||
|
||||
/**
|
||||
* Finds all entities with the given entity template name, that belong to player @p owner.
|
||||
* If @p onScreenOnly then only entities visible on the screen will be selected,
|
||||
* else all entities visible in the world will be selected.
|
||||
*/
|
||||
std::vector<entity_id_t> PickSimilarEntities(CSimulation2& simulation, const CCamera& camera, std::string templateName, int owner, bool onScreenOnly);
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // INCLUDED_SELECTION
|
||||
|
Loading…
Reference in New Issue
Block a user