diff --git a/SpeckleConnector/Connector.vcxproj b/SpeckleConnector/Connector.vcxproj index acf33d4..245709b 100644 --- a/SpeckleConnector/Connector.vcxproj +++ b/SpeckleConnector/Connector.vcxproj @@ -114,6 +114,7 @@ + @@ -169,6 +170,7 @@ + diff --git a/SpeckleConnector/Connector.vcxproj.filters b/SpeckleConnector/Connector.vcxproj.filters index 374c759..763dc5c 100644 --- a/SpeckleConnector/Connector.vcxproj.filters +++ b/SpeckleConnector/Connector.vcxproj.filters @@ -243,6 +243,9 @@ Connector\Interface\Browser\Bridge\Selection\Arg + + Connector\Interface\Browser\Bridge\Selection + @@ -411,5 +414,8 @@ Connector\Interface\Browser\Bridge\Selection\Arg + + Connector\Interface\Browser\Bridge\Selection + \ No newline at end of file diff --git a/SpeckleConnector/Connector/Connector.cpp b/SpeckleConnector/Connector/Connector.cpp index 23943be..4343b1e 100755 --- a/SpeckleConnector/Connector/Connector.cpp +++ b/SpeckleConnector/Connector/Connector.cpp @@ -1,6 +1,7 @@ #include "Active/File/Directory.h" #include "ConnectorResource.h" #include "Connector/Connector.h" +#include "Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h" #include "Connector/Database/ModelCardDatabase.h" #include "Connector/Interface/ConnectorMenu.h" #include "Connector/Interface/ConnectorPalette.h" @@ -12,6 +13,7 @@ using namespace active::file; using namespace active::environment; using namespace connector; using namespace connector::database; +using namespace connector::interfac::browser::bridge; using namespace speckle::database; using namespace speckle::environment; using namespace speckle::utility; diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp index 42611d6..b7126b9 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp @@ -2,6 +2,14 @@ #include "Active/Serialise/Item/Wrapper/ValueWrap.h" #include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Active/Serialise/Package/Wrapper/ContainerWrap.h" + +#include "Connector/Connector.h" + +#include "Speckle/Database/BIMElementDatabase.h" +#include "Speckle/Environment/Project.h" +#include "Speckle/Record/Element/Element.h" +using namespace speckle::record::element; #include @@ -12,16 +20,40 @@ namespace { ///Serialisation fields enum FieldIndex { + selectedObjectIdsID, summaryID, }; ///Serialisation field IDs static std::array fieldID = { + Identity{"selectedObjectIds"}, Identity{"summary"}, }; } +SelectionInfo::SelectionInfo() { + initialize(); +} + +void SelectionInfo::initialize() { + auto project = connector()->getActiveProject().lock(); + if (!project) { + // TODO: handle + } + + auto elementDatabase = project->getElementDatabase(); + auto selected = elementDatabase->getSelection(); + + active::utility::String summary(selected.size()); + summary += " objects selected."; + m_summary = summary; + + for (const auto& link : selected) { + m_selectedElementIds.push_back(link); + } +} + /*-------------------------------------------------------------------- Fill an inventory with the package items @@ -33,6 +65,7 @@ bool SelectionInfo::fillInventory(Inventory& inventory) const { using enum Entry::Type; inventory.merge(Inventory{ { + { fieldID[selectedObjectIdsID], selectedObjectIdsID, element }, { fieldID[summaryID], summaryID, element }, }, }.withType(&typeid(SelectionInfo))); @@ -52,8 +85,10 @@ Cargo::Unique SelectionInfo::getCargo(const Inventory::Item& item) const { return nullptr; using namespace active::serialise; switch (item.index) { + case selectedObjectIdsID: + return std::make_unique>>(m_selectedElementIds); case summaryID: - return std::make_unique>(summary); + return std::make_unique>(m_summary); default: return nullptr; //Requested an unknown index } diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h index 2e81bea..12c9ec3 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h @@ -21,10 +21,12 @@ namespace connector::interfac::browser::bridge { /*! Default constructor */ - SelectionInfo() = default; + SelectionInfo(); - active::utility::String summary = "Nothing is selected"; - std::vector selectedElementIds; + active::utility::String m_summary = "No objects selected"; + std::vector m_selectedElementIds; + + void initialize(); // MARK: - Serialisation diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp index fc239a7..6385c09 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp @@ -1,30 +1,10 @@ #include "Connector/Interface/Browser/Bridge/Selection/GetSelection.h" - #include "Active/Serialise/CargoHold.h" -#include "Active/Serialise/Package/Wrapper/PackageWrap.h" #include "Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h" -#include "Connector/Connector.h" -#include "Connector/Record/Collection/ProjectCollection.h" - -#include "Speckle/Database/BIMElementDatabase.h" -#include "Speckle/Environment/Project.h" -#include "Speckle/Record/Element/Element.h" -using namespace speckle::record::element; - -#include - using namespace active::serialise; using namespace connector::interfac::browser::bridge; -using namespace speckle::utility; -using namespace connector::record; -namespace { - - ///Return type for retrieving the current configuration - using WrappedValue = CargoHold; - -} /*-------------------------------------------------------------------- Default constructor --------------------------------------------------------------------*/ @@ -39,30 +19,6 @@ GetSelection::GetSelection() : BridgeMethod{"GetSelection", [&]() { modelCardID: The ID of the model to send --------------------------------------------------------------------*/ std::unique_ptr GetSelection::run() const { - auto selectionInfo = std::make_unique(); - - auto project = connector()->getActiveProject().lock(); - if (!project) { - // TODO - } - - //Build a collection from the selected elements - auto collection = std::make_unique(project); - auto elementDatabase = project->getElementDatabase(); - auto selected = elementDatabase->getSelection(); - - active::utility::String summary(selected.size()); - summary += " objects selected."; - - selectionInfo->summary = summary; - - for (const auto& link : selected) { - if (auto element = elementDatabase->getElement(link); element) { - collection->addElement(*element); - selectionInfo->selectedElementIds.push_back(element->getBIMID()); - } - } - - return std::make_unique(std::move(selectionInfo)); + return std::make_unique>(std::move(selectionInfo)); } //GetSelection::run diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp index 5fa969f..f31cc98 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp @@ -1,7 +1,9 @@ #include "Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h" - #include "Connector/Interface/Browser/Bridge/Selection/GetSelection.h" +#include "Active/Serialise/CargoHold.h" +#include "Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h" +using namespace active::serialise; using namespace connector::interfac::browser::bridge; /*-------------------------------------------------------------------- @@ -11,3 +13,10 @@ SelectionBridge::SelectionBridge() : BrowserBridge{"selectionBinding"} { //Add bridge methods addMethod(); } //SelectionBridge::SelectionBridge + +bool SelectionBridge::handle(const speckle::event::SelectionEvent& event) { + auto selectionInfo = std::make_unique(); + auto wrapped = std::make_unique>(std::move(selectionInfo)); + sendEvent("setSelection", std::move(wrapped)); + return true; +} diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h index 053fba2..a92f213 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h @@ -2,13 +2,15 @@ #define CONNECTOR_INTERFACE_BRIDGE_SELECTION_BRIDGE #include "Speckle/Interface/Browser/Bridge/BrowserBridge.h" +#include "Speckle/Event/Subscriber/SelectionSubscriber.h" +#include "Speckle/Event/Type/SelectionEvent.h" namespace connector::interfac::browser::bridge { /*! A browser bridge to support sending model data to a Speckle server */ - class SelectionBridge : public speckle::interfac::browser::bridge::BrowserBridge { + class SelectionBridge : public speckle::interfac::browser::bridge::BrowserBridge, public speckle::event::SelectionSubscriber { public: // MARK: - Types @@ -22,6 +24,10 @@ namespace connector::interfac::browser::bridge { Default constructor */ SelectionBridge(); + + protected: + + bool handle(const speckle::event::SelectionEvent& event) override; }; } diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.cpp new file mode 100644 index 0000000..652b96d --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.cpp @@ -0,0 +1,28 @@ +#include "Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h" + +#include "Active/Event/Event.h" +#include "Connector/ConnectorResource.h" +#include "Connector/Event/ConnectorEventID.h" +#include "Speckle/Environment/Addon.h" + +using namespace connector::interfac::browser::bridge; + + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +SelectionChangeHandler::SelectionChangeHandler() { + int i = 0; +} //SelectionChangeHandler::SelectionChangeHandler + +/*-------------------------------------------------------------------- + Handle the menu selection + + event: The menu event + + return: True if the event should be closed + --------------------------------------------------------------------*/ +bool SelectionChangeHandler::handle(const speckle::event::SelectionEvent& event) { + int i = 0; + return true; +} diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h new file mode 100644 index 0000000..38cf52b --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h @@ -0,0 +1,28 @@ +#ifndef CONNECTOR_INTERFACE_BRIDGE_SELECTION_CHANGE_HANDLER +#define CONNECTOR_INTERFACE_BRIDGE_SELECTION_CHANGE_HANDLER + +#include "Speckle/Event/Subscriber/SelectionSubscriber.h" +#include "Speckle/Event/Type/SelectionEvent.h" + +namespace connector::interfac::browser::bridge { + + /*! + Configuration settings class + */ + class SelectionChangeHandler : public speckle::event::SelectionSubscriber { + public: + // MARK: - Constructors + + /*! + Default constructor + */ + SelectionChangeHandler(); + + + protected: + bool handle(const speckle::event::SelectionEvent& event) override; + }; + +} + +#endif //CONNECTOR_INTERFACE_BRIDGE_SELECTION_CHANGE_HANDLER diff --git a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp index 0800691..da4a920 100644 --- a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp +++ b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp @@ -4,6 +4,7 @@ #include "Active/Utility/String.h" #include "Active/Serialise/JSON/JSONTransport.h" #include "Active/Utility/BufferOut.h" +#include "Connector/Connector.h" #include "Connector/ConnectorResource.h" #include "Connector/Event/ConnectorEventID.h" #include "Connector/Interface/Browser/Bridge/Account/AccountBridge.h" @@ -77,9 +78,6 @@ namespace { virtual void PanelResized(const DG::PanelResizeEvent& ev) override; virtual void PanelCloseRequested(const DG::PanelCloseRequestEvent& ev, bool* accepted) override; - static GS::Array GetSelectedElements(); - static void ModifySelection(const GS::UniString& elemGuidStr, SelectionModification modification); - static GSErrCode __ACENV_CALL PaletteControlCallBack(Int32 paletteId, API_PaletteMessageID messageID, GS::IntPtr param); static GS::Ref instance; @@ -171,7 +169,12 @@ BrowserPalette::BrowserPalette() : install(); install(); install(); - install(); + if (auto ref = install(); ref) { + if (auto selectionBridgeRef = std::dynamic_pointer_cast(ref); selectionBridgeRef) { + connector::connector()->addWeak(selectionBridgeRef); + selectionBridgeRef->start(); + } + } install(); InitBrowserControl(); } @@ -245,31 +248,6 @@ void BrowserPalette::PanelCloseRequested(const DG::PanelCloseRequestEvent&, bool *accepted = true; } -GS::Array BrowserPalette::GetSelectedElements() { - API_SelectionInfo selectionInfo; - GS::Array selNeigs; - ACAPI_Selection_Get(&selectionInfo, &selNeigs, false, false); - BMKillHandle((GSHandle*)&selectionInfo.marquee.coords); - - GS::Array selectedElements; - for(const API_Neig& neig : selNeigs) { - API_Elem_Head elemHead = {}; - elemHead.guid = neig.guid; - ACAPI_Element_GetHeader(&elemHead); - - ElementInfo elemInfo; - elemInfo.guidStr = APIGuidToString(elemHead.guid); - ACAPI_Element_GetElemTypeName(elemHead.type, elemInfo.typeName); - ACAPI_Element_GetElementInfoString(&elemHead.guid, &elemInfo.elemID); - selectedElements.Push(elemInfo); - } - return selectedElements; -} - -void BrowserPalette::ModifySelection(const GS::UniString& elemGuidStr, BrowserPalette::SelectionModification modification) { - ACAPI_Selection_Select({ API_Neig(APIGuidFromString(elemGuidStr.ToCStr().Get())) }, modification == AddToSelection); -} - GSErrCode __ACENV_CALL BrowserPalette::PaletteControlCallBack(Int32, API_PaletteMessageID messageID, GS::IntPtr param) { switch(messageID) { case APIPalMsg_OpenPalette: diff --git a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp index 48b5f04..c6925b4 100644 --- a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp +++ b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp @@ -69,12 +69,18 @@ bool SelectionSubscriber::receive(const Event& event) { return: True if the participant is able to continue --------------------------------------------------------------------*/ bool SelectionSubscriber::start() { - if (m_isStarted) - return true; - m_isStarted = true; #ifdef ARCHICAD return (ACAPI_Notification_CatchSelectionChange(selectionCallback) == NoError); #else return false; #endif } //SelectionSubscriber::start + +/*-------------------------------------------------------------------- + Stop participation (release resources etc) + --------------------------------------------------------------------*/ +void SelectionSubscriber::stop() { +#ifdef ARCHICAD + ACAPI_Notification_CatchSelectionChange(nullptr); +#endif +} diff --git a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h index 975eb0c..a5595b0 100644 --- a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h +++ b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h @@ -35,7 +35,7 @@ namespace speckle::event { Get the event subscription list @return The subscription list (an empty list will put the subscriber into a suspended state) */ - virtual Subscription subscription() const override; + Subscription subscription() const override; // MARK: - Functions (mutating) @@ -44,14 +44,21 @@ namespace speckle::event { @param event The incoming event @return True if the event should be closed */ - virtual bool receive(const active::event::Event& event) override; - - protected: + bool receive(const active::event::Event& event) override; + /*! Start the participant operation @return True if the participant is able to continue */ virtual bool start() override; + + /*! + Stop participation (release resources etc) + */ + void stop() override; + + protected: + /*! Handle the menu selection @param event The menu event diff --git a/SpeckleLib/Speckle/Event/Type/SelectionEvent.h b/SpeckleLib/Speckle/Event/Type/SelectionEvent.h index 396f698..365f70f 100644 --- a/SpeckleLib/Speckle/Event/Type/SelectionEvent.h +++ b/SpeckleLib/Speckle/Event/Type/SelectionEvent.h @@ -24,7 +24,7 @@ namespace speckle::event { Constructor @param selected A link to a selected element (nullopt if the selection is empty) */ - SelectionEvent(speckle::database::BIMLink::Option selected) : m_selectedLink{selected} {} + SelectionEvent(speckle::database::BIMLink::Option selected) : Event{ ID }, m_selectedLink{selected} {} /*! Copy constructor @param source The object to copy diff --git a/SpeckleLib/Speckle/Interface/Browser/JSObject.h b/SpeckleLib/Speckle/Interface/Browser/JSObject.h index 05732e6..46843e0 100644 --- a/SpeckleLib/Speckle/Interface/Browser/JSObject.h +++ b/SpeckleLib/Speckle/Interface/Browser/JSObject.h @@ -38,7 +38,7 @@ namespace speckle::interfac::browser { */ template explicit JSObject(const speckle::utility::String& name, const std::initializer_list& items) : base{items}, m_name{name} {} - + virtual ~JSObject() {} // MARK: - Functions (const) /*! diff --git a/SpeckleLib/Speckle/Interface/Browser/JSPortal.h b/SpeckleLib/Speckle/Interface/Browser/JSPortal.h index 14bcc26..159eeb7 100644 --- a/SpeckleLib/Speckle/Interface/Browser/JSPortal.h +++ b/SpeckleLib/Speckle/Interface/Browser/JSPortal.h @@ -48,14 +48,14 @@ namespace speckle::interfac::browser { @param object The object to install @return True if the object was successfully installed */ - bool install(std::shared_ptr> object); + std::shared_ptr> install(std::shared_ptr> object); /*! Install a JS function object @return True if the object was successfully installed @tparam T The type of object to install */ template requires std::is_base_of_v, T> - bool install() { return install(std::make_shared()); } + std::shared_ptr> install() { return install(std::make_shared()); } protected: #ifdef ARCHICAD @@ -101,12 +101,12 @@ namespace speckle::interfac::browser { return: True if the object was successfully installed --------------------------------------------------------------------*/ template - bool JSPortal::install(std::shared_ptr> object) { + std::shared_ptr> JSPortal::install(std::shared_ptr> object) { try { #ifdef ARCHICAD auto engine = getJSEngine(); if (!engine) - return false; + return nullptr; //Define the JS object JS::Object* acObject = new JS::Object(object->getName()); //Add all the functions supported by this object @@ -125,13 +125,13 @@ namespace speckle::interfac::browser { if (engine->RegisterAsynchJSObject(acObject)) { base::push_back(object); object->setPortal(*this); - return true; + return object; } #endif } catch(...) { ///TODO: Need to discuss the best course of action to notify of a failure } - return false; + return nullptr; } //JSPortal::install }