Jump to content


  • Posts

  • Joined

  • Last visited

Everything posted by Hippocode

  1. Option 2 is probably the hardest because you have to be carefull with undo and manage all actions properly for two objects that are "bound" on a parametric base. There is another option 3. In the SDK you can choose if the recalculate event removes everything prior to recreation. The inner object would reside permanently in the outer. For simplicity option 1 is probably the best choice. It also depends of the interaction you need. Does the outer control the inner? Or in reverse order? If it's just a couple fields you could duplicate them in the parent object, which update the inner object with those same fields. This is probably the easiest method. If you use the option of the profile group, the benefit is that you can have a button in the info palette that opens the profile group and preselects the inner object, from that point the inner objec's palette is shown for direct access. On exit, you can have the parent object reset and use the new values. You can also extend the object info palette with custom fields that are linked to any object or data as long as you handle the conversion as you need to bypass the normal translation from/to, I'm doing this with several plug-ins combined with a selector widget (kWidgetSubSelection) that allows me to iterate several inner objects within the object info palette. This is great for a couple fields but those other options are probably better for larger palettes. Some small snippets for indication. bool IProvider_MEPComponent::OnWidgetChange(SShapePaneWidgetOnWidgetChange& data, bool& outNeedReset, bool& outChangeOk) else if(fWidgetsContainer.IsWidget(WidgetId, "ToggleLegs")) { outNeedReset = false; eventHandled = false; using namespace VectorWorks::Extension; if(fLegs.size() > 0) { IShapePaneWidgetAccess::ESubSelButton CurrentButton = data.fWidgetAccess->GetCurrentButton(); if(CurrentButton == IShapePaneWidgetAccess::ESubSelButton::eSubSelButton_CurrentButtonDown) { HighlightActiveLeg(&data); } else if(CurrentButton == IShapePaneWidgetAccess::ESubSelButton::eSubSelButton_NextButtonDown) { fNumActiveLeg++; HighlightActiveLeg(&data); } else if(CurrentButton == IShapePaneWidgetAccess::ESubSelButton::eSubSelButton_PrevButtonDown) { if(fNumActiveLeg == 0) { fNumActiveLeg = fLegs.size() -1; } else { fNumActiveLeg--; } HighlightActiveLeg(&data); } else if(CurrentButton == IShapePaneWidgetAccess::eSubSelButton_CurrentButtonUp || CurrentButton == IShapePaneWidgetAccess::eSubSelButton_NextButtonUp || CurrentButton == IShapePaneWidgetAccess::eSubSelButton_PrevButtonUp) { data.fWidgetAccess->ClearHighlightPoint(); data.fWidgetAccess->SetValueBool(data.fViewWidget, false); } } } You need to manage TransferValue in both directions for widgets not bound to default parameters of your object. In this case I'm referencing data from whichever inner object is the active selection from the previous selector widget. bool IProvider_MEPComponent::TransferValue(VectorWorks::Extension::SShapePaneWidgetTransferValue &data) { using namespace VectorWorks::Extension; bool handled = false; // For some widgets we need to switch over the record format to the active connector... if( fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_DimensionType") || fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Length") || fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Shape") || fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Width") || fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Height") ) { if(fLegs.size() > 0) { sUserData_JunctionLeg* pLeg = &fLegs[fNumActiveLeg % fLegs.size()]; if(data.fTransferToView) { if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_DimensionType")) { TXString strValue; strValue.itoa(pLeg->DimensionType); data.fWidgetAccess->SetValueString(data.fViewWidget, strValue); } if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Width"))data.fWidgetAccess->SetValueString(data.fViewWidget, pLeg->NominalWidth); if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Height"))data.fWidgetAccess->SetValueString(data.fViewWidget, pLeg->NominalHeight); if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Shape")) { TXString strShape; strShape.itoa(pLeg->Shape); data.fWidgetAccess->SetValueString(data.fViewWidget, strShape); } if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Length"))data.fWidgetAccess->SetValueReal(data.fViewWidget, pLeg->Length, IShapePaneWidgetAccess::eRealType_Coord); } else { if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_DimensionType")) { pLeg->DimensionType = (VWFC::VWObjects::sUserData_JunctionLeg::eLegDimensions) data.fWidgetAccess->GetValueString(data.fViewWidget).atoi(); } if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Width"))pLeg->NominalWidth = data.fWidgetAccess->GetValueString(data.fViewWidget); if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Height"))pLeg->NominalHeight = data.fWidgetAccess->GetValueString(data.fViewWidget); if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Shape")) { pLeg->Shape = (eShape) data.fWidgetAccess->GetValueString(data.fViewWidget).atoi(); } if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Length"))pLeg->Length = data.fWidgetAccess->GetValueReal(data.fViewWidget, IShapePaneWidgetAccess::eRealType_Coord); // Save user data back into junction and reset it.. VWMEPJunctionObj JunctionObj(fhObject); JunctionObj.SaveLegs(fLegs); JunctionObj.ResetObject(); } } handled = true; }
  2. I think you can't use a function as a procedure? Try making it return to a boolean value instead. result := SetWallPres...
  3. Set/GetSavedSetting is by far the easiest option to use, but this is more commonly used for settings that surpass the scope of a drawing/document. If you need to remember these settings based on the active file you can also use a custom hidden record with a field for each setting you require.
  4. Make sure you are compiling with at least 10.15, target should be 10.13. If you still have an issue I find the easiest way to tackle this is to start fresh from a sample project and copy over your custom files and settings. Old projects can contain deprecated settings and after a while it's hard to find what is used and what not. Also make sure you compile generic to cover both ARM64 and Intel.
  5. https://developer.vectorworks.net/index.php/VS:GetObject Since the symbol definition is unique you can get the handle using its name. Be sure to verify the object type.
  6. It will be part of the VectorMEP 2022 release which should be available during September 2021.
  7. Yes this is only possible using the SDK. You could create a small SDK project that runs a specific python script on startup or any other event if you don't want to bring over the full script.
  8. You could have a script traverse all the rectangles in that layer, and number them in sequence for you. On default that would be stacking order, but you could also use coordinates to define the order instead, like relative position.
  9. Well how I see it this is about two main functions. You need to automate the creation of certain objects (layers, rooms, sheets) You need to update the data of these objects. I'd assume this external info could change during the project development like updating room names. The input for both could be based from Excell or a Worksheet (imported Excell) or any input dialog whatever fits your needs. Both can be done with Vectorscript. A lot can go wrong so It'll be trial and error to develop this. FYI, I'm working on a new plug-in that allows you to export object data (for instance all rooms with their name, custom parameters etc) to Excell. Modify or append this data in Excell and import it back into the drawing, updating all these objects with the new data.
  10. For a simple standard a basic file or template as mentioned earlier is the way to go. If you need it to be more flexible with additional data, or generic from a source like Excell yes a script is a good option. It should be possible iterating all the cells from a Worksheet and do something with it.
  11. Think of the OnCursorAction triggers as a tool, you need to start it before the others will be triggered. And it starts with triggering a controlpoint by clicking/hovering it I guess. The other functions just show the images and text and decide if they should be visible, those are triggered constantly probably. I believe non parametric control points have positive index values, parametric ones negative. you can mix the use of them but it's important to return true/false properly @ IsDefaultCursorHandled Sint32 Index = context->GetCustomPtClientID(); // Index of CP I believe there are a lot of inconsistencies in those interfaces. For me I know that ICursorHandleActionContext::GetObject not always returns the effective object (or didn't in the past). For that reason I keep a copy of the handle in the interface itself and update it whenever GetObject does return a value in any of those functions. This ensures the other functions know which object we are managing the controlpoints for regardless of the provided context.
  12. I'm using the CParametricCustomBar wrapper class instead. This example comes from a cursor event that shows and allows to change the angle between two lines. I initiate it on OnCursorAction_MouseDown on first click fAngleBar.ClearFields(); fAngleBar.AddField("A:"); fAngleBar.SetFieldLock(0, false); fAngleBar.Create(); fAngleBar.SetUp(); fAngleBar.Install(); On any other click, within the same function I close it because what I was doing has completed. fAngleBar.Release(); while mousemove I modify the value to match the situation: gSDK->CustomBarSetFieldAngle(fAngleBar.GetCustomBarID(), 0, Utility::GetAngleBetweenVectors(-V1, VDir));
  13. You can handle creation/deletion/position as mentioned on that page. Depending on how flexible this should be I do this on kobjectCreated event or in the recalc event. But for managing the images, displayed hover text and other specific actions I advice to use the IProviderCursorHandles interface. This also replaces the old code you mentioned. The interface will catch these events.
  14. Hi Julian I have only tested this with the SDK but this is the equivalent function in VS. https://developer.vectorworks.net/index.php/VS:EditObjectSpecial The kObjXPropSpecialEditEditGroup constant should get you into the profile group. I'm calling this from a button widget on the OIP. const TObjSpecialEdit kObjXPropSpecialEditDefault = 0; const TObjSpecialEdit kObjXPropSpecialEditCustom = 1; const TObjSpecialEdit kObjXPropSpecialEditProperties = 2; const TObjSpecialEdit kObjXPropSpecialEditReshape = 3; const TObjSpecialEdit kObjXPropSpecialEditEditGroup = 4; const TObjSpecialEdit kObjXPropSpecialEditSpecial = 5;
  15. It seems that the editing dialog / OIP controls the data and since the record is read only you won't have access. I couldn't find anything in the SDK related to this special hidden record type (besides some kludge calls) . I find it interesting myself as I'd like to have readonly records as well; @Vlado Is this feature exposed to VS / SDK?
  16. The typical way is to hide it from the resource browser. Just like object format records are not visible. If that isn't sufficient you might try working with catching the kNotifyRecordChange event but I doubt you can catch the exact change, you could compare this from a default sitting in your resource library.
  17. For exactly the same reason I did save this data within the plug-in itself. I attached the data to the object handle itself or using parameters. Because the objects are accessible you can determine versions etc..
  18. I believe when creating a symbol from the VWSymbolObj wrapper class it's not properly attached to a container, in your case the active layer. Try additing it manually after you create the symbol, and before you reset it using "gSDK->AddObjectToContainer"
  19. Have a look in this topic: If you don't create something, your can use other functions to traverse the workspace, find the palette by name or identifier and use that handle to show/hide these.
  20. Well it could be any of these settings. I'm setting all these to show the palette in a specific spot. bool inTearOffState = false; bool inTopPosition = false; Sint16 ToolinSortStyle = 1; Sint16 ToolinViewStyle = 2; Sint16 ToolSetinSortStyle = 1; Sint16 ToolSetinViewStyle = 2; bool inVisibilityState = true; bool inWindowShadeState = false; EWindowHomeCorner inHomeCorner = EWindowHomeCorner::eWindowHomeCorner_ScreenUpperLeft; Sint16 inHorizontalOffset = 0; Sint16 inVerticalOffset = 0; ViewRect screenRect; gSDK->GetScreenSize(screenRect); ViewPt Center = screenRect.Center(); inHorizontalOffset = +Center.x; inVerticalOffset = +Center.y; if(VCOM_SUCCEEDED(errorCode)) errorCode = pToolPalette->SetTearOffState(inTearOffState); if(VCOM_SUCCEEDED(errorCode)) errorCode = pToolPalette->SetToolSetPosition(inTopPosition); if(VCOM_SUCCEEDED(errorCode)) errorCode = pToolPalette->SetToolSetSortStyle(ToolSetinSortStyle); if(VCOM_SUCCEEDED(errorCode)) errorCode = pToolPalette->SetToolSetViewStyle(ToolSetinViewStyle); if(VCOM_SUCCEEDED(errorCode)) errorCode = pToolPalette->SetToolViewStyle(ToolinViewStyle); if(VCOM_SUCCEEDED(errorCode)) errorCode = pToolPalette->SetToolSortStyle(ToolinSortStyle); if(VCOM_SUCCEEDED(errorCode)) errorCode = pToolPalette->SetVisibilityState(inVisibilityState); if(VCOM_SUCCEEDED(errorCode)) errorCode = pToolPalette->SetWindowShadeState(inWindowShadeState); if(VCOM_SUCCEEDED(errorCode)) errorCode = pToolPalette->SetHomeCorner(inHomeCorner); if(VCOM_SUCCEEDED(errorCode)) errorCode = pToolPalette->SetHomeCornerOffset(inHorizontalOffset, inVerticalOffset);
  21. Is there any way we can provide a link to our own help documentation/wiki when creating tools with the SDK? When you hit F1 on default tools you end up on the specific article explained in the Vectorworks help.
  22. Make sure that the workspace interfaces are initiated correctly. This is a snippet of my workspace wrapper class and confirmed to be working: VCOMPtr<IWorkspaces> pWorkspace(IID_Workspaces); // Get current workspace file name. TXString workspaceFileName; gSDK->GetCurrentWorkspaceFile(workspaceFileName); // Current workspace full file name. TXString workspaceFullFileName = workspaceFileName + ".vww"; VCOMPtr<IWorkspaceFile> pWorkspaceFile(IID_WorkspaceFile); if(pWorkspaceFile && pWorkspace) { errorCode = pWorkspaceFile->Open(workspaceFullFileName, kFileReadPermission); VCOMPtr< IWorkspaceToolPalette > pToolPalette; VCOMPtr< IWorkspaceTool > pTool; TXString ToolPaletteName = "VectorMEP"; TXString ToolPaletteIdentifier; if(VCOM_SUCCEEDED(errorCode)) errorCode = pWorkspace->CreateIdentifier(VectorWorks::Workspaces::EWorkspaceItemType::eWorkspaceItemType_ToolPalette, ToolPaletteIdentifier); if(VCOM_SUCCEEDED(errorCode)) errorCode = pWorkspaceFile->CreateToolPalette(ToolPaletteIdentifier, &pToolPalette); pToolPalette->SetDisplayName(ToolPaletteName);
  23. In short: Only the creator of the voids requires a VectorMEP license. All the other communication tools are free. The mapping tool allows you to predefine filters of objects you would like to compare. For instances all pipes versus floors. You can even define a parameter value to filter even further. You can also setup additional dimensions when creating voids, based on some categories. If you map a "pipe" as "Plumbing" category, the additional offsets will be used as set in the dimensions dialog. Person A creates the voids by selecting the mappings. Person B references the file that contains the voids. Person B can now manage the status and comments of these voids within his own project. Person B can export his modifications to an XML file. Person A imports the XML file, which updates the status and any comments of each void. This process can be repeated. Note the the openings are only created for those objects that support it, but in both cases the void object will be present. You can create unlimited void mappings based on object names and optionally based on a parameter value. Also supports custom objects. I'm about to update some of it's functionality so wait a tiny bit if you plan on testing it out.
  24. This plug-in is part of our VectorMEP bundle. It's not meant to be a clashing tool, but rather a tool that automates openings and allows you to communicate about it. While the example shows automated voids between pipes and walls, the tool allows you to select any kind of "clashing" object, thus not limited to MEP design. It also allows you to export/import voids between users as a communication tool. You can add comments, accept or deny void suggestions etc... Showcase video:
  • Create New...