Ticket #515: TripleClick.patch

File TripleClick.patch, 10.4 KB (added by Evans, 13 years ago)
  • source/gui/scripting/ScriptFunctions.cpp

     
    128128    return EntitySelection::PickEntitiesInRect(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x0, y0, x1, y1, player);
    129129}
    130130
     131std::vector<entity_id_t> PickSimilarFriendlyEntities(void* UNUSED(cbdata), std::string templateName, bool onScreenOnly)
     132{
     133    return EntitySelection::PickSimilarEntities(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), templateName, g_Game->GetPlayerID(), onScreenOnly);
     134}
     135
    131136CFixedVector3D GetTerrainAtPoint(void* UNUSED(cbdata), int x, int y)
    132137{
    133138    CVector3D pos = g_Game->GetView()->GetCamera()->GetWorldCoordinates(x, y, true);
     
    374379    // Entity picking
    375380    scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, int, &PickEntitiesAtPoint>("PickEntitiesAtPoint");
    376381    scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, int, int, int, int, &PickFriendlyEntitiesInRect>("PickFriendlyEntitiesInRect");
     382    scriptInterface.RegisterFunction<std::vector<entity_id_t>, std::string, bool, &PickSimilarFriendlyEntities>("PickSimilarFriendlyEntities");
    377383    scriptInterface.RegisterFunction<CFixedVector3D, int, int, &GetTerrainAtPoint>("GetTerrainAtPoint");
    378384
    379385    // Network / game setup functions
  • source/simulation2/helpers/Selection.cpp

     
    2323#include "simulation2/Simulation2.h"
    2424#include "simulation2/components/ICmpOwnership.h"
    2525#include "simulation2/components/ICmpRangeManager.h"
     26#include "simulation2/components/ICmpTemplateManager.h"
    2627#include "simulation2/components/ICmpSelectable.h"
    2728#include "simulation2/components/ICmpVisual.h"
    2829
     
    130131
    131132    return hitEnts;
    132133}
     134
     135std::vector<entity_id_t> EntitySelection::PickSimilarEntities(CSimulation2& simulation, const CCamera& camera, std::string templateName, int owner, bool onScreenOnly)
     136{
     137    CmpPtr<ICmpTemplateManager> cmpTemplateManager(simulation, SYSTEM_ENTITY);
     138    std::wstring entVisualActor(L"");
     139    std::vector<entity_id_t> hitEnts;
     140
     141    std::vector<entity_id_t> entities = cmpTemplateManager->GetEntitiesUsingTemplate(templateName);
     142    for (std::vector<entity_id_t>::iterator it = entities.begin(); it != entities.end(); ++it)
     143    {
     144        entity_id_t ent = *it;
     145        // Ignore entities not owned by 'owner'
     146        CmpPtr<ICmpOwnership> cmpOwnership(simulation.GetSimContext(), ent);
     147        if (cmpOwnership.null() || cmpOwnership->GetOwner() != owner)
     148            continue;
     149
     150        // Find the current interpolated model position.
     151        // (We just use the centre position and not the whole bounding box, because maybe
     152        // that's better for users trying to select objects in busy areas)
     153        CmpPtr<ICmpVisual> cmpVisual(simulation.GetSimContext(), ent);
     154        if (cmpVisual.null())
     155            continue;
     156        CVector3D position = cmpVisual->GetPosition();
     157
     158        // Reject if it's not on-screen (e.g. it's behind the camera)
     159        if (onScreenOnly && !camera.GetFrustum().IsPointVisible(position))
     160            continue;
     161
     162        // Take all remaining units, whose template matches the input template
     163        if (cmpTemplateManager->GetCurrentTemplateName(ent) == templateName)
     164            hitEnts.push_back(ent);
     165    }
     166    return hitEnts;
     167
     168}
  • source/simulation2/helpers/Selection.h

     
    4747 */
    4848std::vector<entity_id_t> PickEntitiesInRect(CSimulation2& simulation, const CCamera& camera, int sx0, int sy0, int sx1, int sy1, int owner);
    4949
     50/**
     51 * Finds a selectable entity under the given screen coordinate
     52 * and returns all units with the same visualActors short name,
     53 * when onScreenOnly is set, only Units on screen are returned.
     54 */
     55std::vector<entity_id_t> PickSimilarEntities(CSimulation2& simulation, const CCamera& camera, std::string templateName, int owner, bool onScreenOnly);
     56
    5057} // namespace
    5158
    5259#endif // INCLUDED_SELECTION
  • source/simulation2/components/ICmpTemplateManager.h

     
    8080    virtual std::string GetCurrentTemplateName(entity_id_t ent) = 0;
    8181
    8282    /**
     83     * Returns the list of entities having the specified template
     84     */
     85    virtual std::vector<entity_id_t> GetEntitiesUsingTemplate(std::string templateName) = 0;
     86    /**
    8387     * Returns a list of strings that could be validly passed as @c templateName to LoadTemplate.
    8488     * (This includes "actor|foo" etc names).
    8589     * Intended for use by the map editor. This is likely to be quite slow.
  • source/simulation2/components/CCmpTemplateManager.cpp

     
    131131
    132132    virtual std::vector<std::wstring> FindAllTemplates();
    133133
     134    virtual std::vector<entity_id_t> GetEntitiesUsingTemplate(std::string templateName);
     135
    134136private:
    135137    // Entity template XML validator
    136138    RelaxNGValidator m_Validator;
     
    405407    return templates;
    406408}
    407409
     410std::vector<entity_id_t> CCmpTemplateManager::GetEntitiesUsingTemplate(std::string templateName)
     411{
     412    std::vector<entity_id_t> entities;
     413    for (std::map<entity_id_t, std::string>::const_iterator it = m_LatestTemplates.begin(); it != m_LatestTemplates.end(); ++it)
     414    {
     415        if(it->second.compare(templateName) == 0)
     416            entities.push_back(it->first);
     417    }
     418    return entities;
     419}
     420
    408421void CCmpTemplateManager::CopyPreviewSubset(CParamNode& out, const CParamNode& in, bool corpse)
    409422{
    410423    // We only want to include components which are necessary (for the visual previewing of an entity)
  • source/simulation2/components/ICmpTemplateManager.cpp

     
    2525DEFINE_INTERFACE_METHOD_1("GetTemplate", const CParamNode*, ICmpTemplateManager, GetTemplate, std::string)
    2626DEFINE_INTERFACE_METHOD_1("GetCurrentTemplateName", std::string, ICmpTemplateManager, GetCurrentTemplateName, entity_id_t)
    2727DEFINE_INTERFACE_METHOD_0("FindAllTemplates", std::vector<std::wstring>, ICmpTemplateManager, FindAllTemplates)
     28DEFINE_INTERFACE_METHOD_1("GetEntitiesUsingTemplate", std::vector<entity_id_t>, ICmpTemplateManager, GetEntitiesUsingTemplate, std::string)
    2829END_INTERFACE_WRAPPER(TemplateManager)
  • binaries/data/mods/public/gui/session_new/input.js

     
    3838specialKeyStates[SDLK_RALT] = 0;
    3939specialKeyStates[SDLK_LALT] = 0;
    4040
     41//Number of pixels the mouse can move before the action is considered a drag
     42var maxDragDelta = 4;
     43
     44//Time in milliseconds in which a double click is recognized
     45const doubleClickTime = 500; 
     46var doubleClickTimer = 0;
     47var doubleClicked = false;
     48//Store the previously clicked entity - ensure a double/triple click happens on the same entity
     49var prevClickedEntity = 0;
    4150// (TODO: maybe we should fix the hotkey system to be usable in this situation,
    4251// rather than hardcoding Shift into this code?)
    4352
     
    125134            var playerOwned = ((targetState.player == entState.player)? true : false);
    126135            var enemyOwned = ((targetState.player != entState.player)? true : false);
    127136            var gaiaOwned = ((targetState.player == 0)? true : false);
    128 
    129137           
    130138            if (targetState.garrisonHolder && playerOwned && ctrlPressed)
    131139            {
     
    571579            // If the mouse moved further than a limit, switch to bandbox mode
    572580            var dragDeltaX = ev.x - dragStart[0];
    573581            var dragDeltaY = ev.y - dragStart[1];
    574             var maxDragDelta = 4;
     582           
    575583            if (Math.abs(dragDeltaX) >= maxDragDelta || Math.abs(dragDeltaY) >= maxDragDelta)
    576584            {
    577585                inputState = INPUT_BANDBOXING;
     
    586594            if (ev.button == SDL_BUTTON_LEFT)
    587595            {
    588596                var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y);
     597                var selectedEntity;
     598                var onScreenOnly;
     599               
     600                var now = new Date();
    589601                if (!ents.length)
    590602                {
    591603                    g_Selection.reset();
    592604                    inputState = INPUT_NORMAL;
    593605                    return true;
    594606                }
     607                else
     608                {
     609                    selectedEntity = ents[0];
     610                }
     611                if ((now.getTime() - doubleClickTimer < doubleClickTime) && (selectedEntity == prevClickedEntity))
     612                {
     613                    //Double click or triple click has occured
     614                   
     615                    //Check for double click or triple click
     616                    if (!doubleClicked)
     617                    {
     618                        //If double click hasn't already occured
     619                        //It's a double click
     620                        //Select only similar on-screen units
     621                        onScreenOnly = true;
     622                        doubleClicked = true;
     623                    }
     624                    else
     625                    {
     626                        //Double click has already occured
     627                        //This is a triple click
     628                        //Select all similar units whether they are on-screen or not
     629                        onScreenOnly = false;
     630                    }
     631                   
     632                    var templateToMatch = Engine.GuiInterfaceCall("GetEntityState", selectedEntity).template;
     633                   
     634                    ents = Engine.PickSimilarFriendlyEntities(templateToMatch, onScreenOnly);
     635                }
     636                else
     637                {
     638                    //It's single click right now but it may become double or triple click
     639                    doubleClicked = false;
     640                    doubleClickTimer = now.getTime();
     641                    prevClickedEntity = selectedEntity;
     642                }
    595643
    596644                // If shift is pressed, don't reset the selection, but allow units to be added to the existing selection
    597645                var addition = (specialKeyStates[SDLK_RSHIFT] || specialKeyStates[SDLK_LSHIFT]);
    598646                if (!addition)
    599                     g_Selection.reset();
    600 
    601                 g_Selection.addList([ents[0]]);
     647                    g_Selection.reset();
     648                if (doubleClicked)
     649                {
     650                    //Either double clicked or triple clicked
     651                    //So we add all picked units to the selection
     652                    g_Selection.addList(ents);
     653                }
     654                else
     655                {
     656                    //We add only the first picked unit to the selection
     657                    g_Selection.addList([ents[0]]);
     658                }
     659               
    602660                inputState = INPUT_NORMAL;
    603661                return true;
    604662            }