selectionBridge works

This commit is contained in:
David Kekesi
2024-10-16 15:08:34 +02:00
parent def9162e4c
commit 511311eb84
16 changed files with 160 additions and 95 deletions
+2
View File
@@ -114,6 +114,7 @@
<ClCompile Include="Connector\Interface\Browser\Bridge\Selection\Arg\SelectionInfo.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Selection\GetSelection.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Selection\SelectionBridge.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Selection\SelectionChangeHandler.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Send\Arg\ConversionResult.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Send\Arg\SendError.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Send\Arg\SendObject.cpp" />
@@ -169,6 +170,7 @@
<ClInclude Include="Connector\Interface\Browser\Bridge\Selection\Arg\SelectionInfo.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Selection\GetSelection.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Selection\SelectionBridge.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Selection\SelectionChangeHandler.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Send\Arg\ConversionResult.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Send\Arg\SendError.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Send\Arg\SendObject.h" />
@@ -243,6 +243,9 @@
<ClCompile Include="Connector\Interface\Browser\Bridge\Selection\Arg\SelectionInfo.cpp">
<Filter>Connector\Interface\Browser\Bridge\Selection\Arg</Filter>
</ClCompile>
<ClCompile Include="Connector\Interface\Browser\Bridge\Selection\SelectionChangeHandler.cpp">
<Filter>Connector\Interface\Browser\Bridge\Selection</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Connector\ConnectorResource.h">
@@ -411,5 +414,8 @@
<ClInclude Include="Connector\Interface\Browser\Bridge\Selection\Arg\SelectionInfo.h">
<Filter>Connector\Interface\Browser\Bridge\Selection\Arg</Filter>
</ClInclude>
<ClInclude Include="Connector\Interface\Browser\Bridge\Selection\SelectionChangeHandler.h">
<Filter>Connector\Interface\Browser\Bridge\Selection</Filter>
</ClInclude>
</ItemGroup>
</Project>
+2
View File
@@ -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;
@@ -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 <array>
@@ -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<ContainerWrap<std::vector<active::utility::Guid>>>(m_selectedElementIds);
case summaryID:
return std::make_unique<ValueWrap<active::utility::String>>(summary);
return std::make_unique<ValueWrap<active::utility::String>>(m_summary);
default:
return nullptr; //Requested an unknown index
}
@@ -21,10 +21,12 @@ namespace connector::interfac::browser::bridge {
/*!
Default constructor
*/
SelectionInfo() = default;
SelectionInfo();
active::utility::String summary = "Nothing is selected";
std::vector<active::utility::Guid> selectedElementIds;
active::utility::String m_summary = "No objects selected";
std::vector<active::utility::Guid> m_selectedElementIds;
void initialize();
// MARK: - Serialisation
@@ -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 <array>
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<PackageWrap, SelectionInfo>;
}
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
@@ -39,30 +19,6 @@ GetSelection::GetSelection() : BridgeMethod{"GetSelection", [&]() {
modelCardID: The ID of the model to send
--------------------------------------------------------------------*/
std::unique_ptr<Cargo> GetSelection::run() const {
auto selectionInfo = std::make_unique<SelectionInfo>();
auto project = connector()->getActiveProject().lock();
if (!project) {
// TODO
}
//Build a collection from the selected elements
auto collection = std::make_unique<ProjectCollection>(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<WrappedValue>(std::move(selectionInfo));
return std::make_unique<CargoHold<PackageWrap, SelectionInfo>>(std::move(selectionInfo));
} //GetSelection::run
@@ -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<GetSelection>();
} //SelectionBridge::SelectionBridge
bool SelectionBridge::handle(const speckle::event::SelectionEvent& event) {
auto selectionInfo = std::make_unique<SelectionInfo>();
auto wrapped = std::make_unique<CargoHold<PackageWrap, SelectionInfo>>(std::move(selectionInfo));
sendEvent("setSelection", std::move(wrapped));
return true;
}
@@ -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;
};
}
@@ -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;
}
@@ -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
@@ -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<BrowserPalette::ElementInfo> 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<BrowserPalette> instance;
@@ -171,7 +169,12 @@ BrowserPalette::BrowserPalette() :
install<BaseBridge>();
install<ConfigBridge>();
install<SendBridge>();
install<SelectionBridge>();
if (auto ref = install<SelectionBridge>(); ref) {
if (auto selectionBridgeRef = std::dynamic_pointer_cast<SelectionBridge>(ref); selectionBridgeRef) {
connector::connector()->addWeak(selectionBridgeRef);
selectionBridgeRef->start();
}
}
install<TestBridge>();
InitBrowserControl();
}
@@ -245,31 +248,6 @@ void BrowserPalette::PanelCloseRequested(const DG::PanelCloseRequestEvent&, bool
*accepted = true;
}
GS::Array<BrowserPalette::ElementInfo> BrowserPalette::GetSelectedElements() {
API_SelectionInfo selectionInfo;
GS::Array<API_Neig> selNeigs;
ACAPI_Selection_Get(&selectionInfo, &selNeigs, false, false);
BMKillHandle((GSHandle*)&selectionInfo.marquee.coords);
GS::Array<BrowserPalette::ElementInfo> 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:
@@ -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
}
@@ -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
@@ -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
@@ -38,7 +38,7 @@ namespace speckle::interfac::browser {
*/
template<class Derived>
explicit JSObject(const speckle::utility::String& name, const std::initializer_list<Derived>& items) : base{items}, m_name{name} {}
virtual ~JSObject() {}
// MARK: - Functions (const)
/*!
@@ -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<JSObject<FunctionBinding>> object);
std::shared_ptr<JSObject<FunctionBinding>> install(std::shared_ptr<JSObject<FunctionBinding>> object);
/*!
Install a JS function object
@return True if the object was successfully installed
@tparam T The type of object to install
*/
template<typename T> requires std::is_base_of_v<JSObject<FunctionBinding>, T>
bool install() { return install(std::make_shared<T>()); }
std::shared_ptr<JSObject<FunctionBinding>> install() { return install(std::make_shared<T>()); }
protected:
#ifdef ARCHICAD
@@ -101,12 +101,12 @@ namespace speckle::interfac::browser {
return: True if the object was successfully installed
--------------------------------------------------------------------*/
template<typename FunctionBinding>
bool JSPortal<FunctionBinding>::install(std::shared_ptr<JSObject<FunctionBinding>> object) {
std::shared_ptr<JSObject<FunctionBinding>> JSPortal<FunctionBinding>::install(std::shared_ptr<JSObject<FunctionBinding>> 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<FunctionBinding>::install
}