public double cm.abstract.dataSymbol.ui.lerp(double from, double to, double lerpTo) : inline public int cm.abstract.dataSymbol.ui.lerp(int from, int to, double lerpTo) : inline extend public double DsFreeformPicklistItem::actualQuantity(); private DsFreeformItem DsFreeformPicklistPart._item : copy=reference; extend public void DsFreeformGridWindow::forceSelect(pointI p); Old: public void addPropagateProperties(PropDefs defs) { New: public void dsAddPropagateProperties(PropDefs defs) { Old: public void addElevationProperty(PropDefs defs) { New: public void dsAddElevationProperty(PropDefs defs) {
Notes:
public class AisleManager public class PHNode final public bool ShelvingGraphicVessel::isDoublePalletRackBody() public void PHBodyDragAnimationG2::moveMultiSelect(bool refreshMouseInfo=false)
Due to the removal of the AisleManager
class all methods of the AisleManager
has been moved to the NoAislePHBody
class. During this move some methods also got renamed to clarify the purpose of the methods.
Old: extend public PHBody ShelvingGraphicVessel::palletRactBody() New: extend public PHBody ShelvingGraphicVessel::phBody() Old: public double getPotentialAisleWidth(PHBody main, PHBody otherPHBody) New: public double edgeToEdgeDistance(PHBody main, PHBody other) Old: public point getMainPositionGivenAisleWidth(NoAislePHBody other, NoAislePHBody main, double aisleWidth) New: public point adjustPositionToAisleWidth(PHBody main, PHBody other, double aisleWidth) Old: public ShelvingBody{} getAllGroupShelving(ShelvingBody body) New: public ShelvingBody{} getSystemShelving(ShelvingBody body) Old: public ShelvingBody{} getAllGroupShelving(NoAislePHBody phBody) New: public ShelvingBody{} getSystemShelving(NoAislePHBody phBody) Old: public bool isAboveOtherBody(NoAislePHBody main, NoAislePHBody other) New: public bool isAboveOtherBody(PHBody main, PHBody other) Old: public NoAislePHBody getClosestPHBodyInSpace(Space space, point onFloorPos) New: public PHBody getClosestPHBodyInSpace(Space space, point onFloorPos, double searchR=3m, SnapperFilter filter=PHBodyFilter()) Old: final public bool LOPositionEnv::isConflicts(box b1, box b2) New: extend public bool LOPositionEnv::conflicts(box b1, box b2) Old: extend public void PHBodyInsertAnimationG2::tryUpdateAisle(NoAislePHBody oldClosest) New: extend public void PHBodyInsertAnimationG2::updateAisleWidth(NoAislePHBody oldClosest) Old: extend public void PHBodyInsertAnimationG2::tryUpdateMainBody() New: extend public void PHBodyInsertAnimationG2::updateMainBody() Old: extend public double PHBodyInsertAnimationG2::getClosestAisle() New: extend public double PHBodyInsertAnimationG2::getClosestAisleWidth() Old: public double AisleManager::bottomAisle New: extend public double NoAislePHBody::getAisleWidth() New: extend public void NoAislePHBody::setAisleWidth(double newAisleWidth) Old: extend public double AisleManager::initialAisleWidth() New: extend public double NoAislePHBody::initialAisleWidth() Old: extend public NoAislePHBody AisleManager::getTopMost() New: extend public NoAislePHBody NoAislePHBody::getTopMost() Old: extend public NoAislePHBody AisleManager::isTopMost() New: extend public NoAislePHBody NoAislePHBody::isTopMost() Old: extend public NoAislePHBody AisleManager::getBotMost() New: extend public NoAislePHBody NoAislePHBody::getBottomMost() Old: extend public NoAislePHBody AisleManager::isBotMost() New: extend public NoAislePHBody NoAislePHBody::isBottomMost() Old: extend public NoAislePHBody AisleManager::getClosestPHBody(bool top=true) New: extend public NoAislePHBody NoAislePHBody::getClosestPHBody(bool top=true) Old: extend public NoAislePHBody[] AisleManager::getAllPHBody() New: extend public NoAislePHBody[] NoAislePHBody::phSystemGroup() Old: extend public NoAislePHBody[] AisleManager::getAllPHBodyAccordingToDirection(bool top) New: extend public NoAislePHBody[] NoAislePHBody::phDirectionGroup(bool top) Old: extend public Snapper{} AisleManager::getAllRelatedSnappers() New: extend public Snapper{} NoAislePHBody::allConnectedSnappers() Old: extend public void NoAislePHBody::resetNodeAndRebuild2D() New: extend public void NoAislePHBody::unlinkAndRebuild2D() Old: extend public box ShelvingSystemOutlineVessel::getSystemBound(PHNode node) New: extend public box ShelvingSystemOutlineVessel::getSystemBound(NoAislePHBody ph) Old: extend public ShelvingSystemOutlineVessel::PHNode getClosestSystemRootNode() New: extend public ShelvingSystemOutlineVessel::NoAislePHBody getClosestPHBody()
_scheme
field have been added to cm.abstract.kitchen.KitchenSnapper
and removed from cm.abstract.kitchen.Rack
ChangedScheme()
added to KitchenSnapper
.
_scheme
field has been removed from subclasses in Abstract Labs, since it´s been added to cm.abstract.kitchen.KitchenSnapper
.
LabsElevationAutoInsertEnv
needs class types passed in as argument rather than an instantiated LabsElevationArrow
object.
Constructor modified on LabsElevationAutoInsertEnv
:
/** * Creation. */ public constructor(LabsElevationArrow frontElev, LabsElevationArrow sideElev, LabsElevationArrow worktopElev, LabsElevationArrow rightSideElev=null, LabsElevationArrow backElev=null) { elevationAutoInsert(frontElev, sideElev, worktopElev, rightSideElev, backElev); }
New constructor cm.abstract.labs.LabsElevationAutoInsertEnv
:
/** * Creation. */ public constructor(Class frontElev, Class leftElev, Class worktopElev, Class rightElev=null, Class backElev=null) { if (frontElev.extends() in ElevArrow) this.frontElev = frontElev; if (leftElev.extends() in ElevArrow) this.leftElev = leftElev; if (worktopElev.extends() in ElevArrow) this.worktopElev = worktopElev; if (rightElev.extends() in ElevArrow) this.rightElev = rightElev; if (backElev.extends() in ElevArrow) this.backElev = backElev; elevationAutoInsert(); }
WorksurfaceSearch
and WsPanelSearch
have been cleaned up and some methods have been renamed to be more clear. WsPanelSearch
was moved to it's own file.
Added updateConnectors()
to PanelJunctionSnapper
.
OfficeSpecOption
now has a field exportable
that can be used for exports (specifically custom SIF) to prevent the option from exporting.
Added a method on PanelFrame
for getting panels that are tmounted on a specific side.
extend public PanelFrame{} getTMountedPanels(bool up)
extend public double worksurfaceBottom()
public OfficeMaterialDialog showOfficeMaterialDialog(Window window, MaterialDomain domain, Material selected, OfficeMaterialLimb limb=null, MaterialSchemeProperty schemeProp=null, str label=null)
OfficeMaterialLimb
supports the label that can be passed into the Office Material Dialog with a change to the showMaterialDialog()
method./** * Show material dialog. */ extend public void showMaterialDialog(Material m, str label=null) { showOfficeMaterialDialog(session.mainWindow, domain, m, this, label=label); }
The CustomerOwnMaterials
object is stored as an AuxillaryObject
now. There is now a global key for getting them, cAOCustomerOwnMatsKey
.
Renamed function getNewH()
to getNewHeight()
.
Added parameter str->Object args
to methods on Worksurface
for creating/updating WorksurfaceConnectLines
and WorksurfaceConnectArc
. This was to allow prop data to be passed from the path members to all parts of the connector generation process.
public void createUpdateConnectLine(str id, worksurfaceConnectType ct, WorksurfacePathLineTo m, point2D last, str->WorksurfaceConnectLine currLines, str->Object args=null) public WorksurfaceConnectLine createWksfConnectLine(line2D ln, str edgeId, worksurfaceConnectType ct, ConnectRule rule=null, str->Object args=null) public void updateWksfConnectLine(WorksurfaceConnectLine wcl, line2D ln, worksurfaceConnectType ct, ConnectRule rule=null, str->Object args=null)
XAPI
instead of PropDefs
.Old: public props { (AShape2D[]) "holes" : { Object get(..) { return that.getCutouts(); } } } New: public xapi { public (AShape2D[]) getCutouts(WorksurfacePath p); }
WorksurfacePathLineTo
and WorksurfacePathArcTo
have had the id
field changed to edgeId
to be more consistent with the edgeId
field on the connectors that get generated.Old: public str id; New: public str edgeId;
seq<str, str8, cstr ..: isort()
and isorted()
previously did regular sort()
, this issue has been rectified.
In 11.0 part tags no longer add a user category on snappers for visibility. Instead the snappers now iterate over explicit tags and applied tags to add to the layerSet
from visibility2D()
and visibility3D()
.
This also means that the part tag categories will no longer be added to the category registry.
rebuildPartTaggingCategories()
is now removed since there are no longer any user categories to rebuild.
/** * Visibility 2D. * This is a visibility summary over graphs currently produced by the snapper. This is used for visibility filtering on snapper level. * * If the snapper produces graphs G1, G2, ... GN, with corresponding layer expressions Exp1, Exp2,... ExpN. * The returned expression should be equivalent to "or(Exp1, Exp2,... ExpN)". */ extend public LayerExpr visibility2D() { if (!layer) { layer = categoryVisibility(); if (explicitTags or appliedPartTags.any) layer = or (layer, partTagVisibility()); if (chunkId or sectionIdG2) layer = or (layer, collaborationVisibility()); } return layer; } /** * Visibility 3D (similar to visibility 2D) */ extend public LayerExpr visibility3D() { if (!layer) { layer = categoryVisibility(); if (explicitTags or appliedPartTags.any) layer = or (layer, partTagVisibility()); if (chunkId or sectionIdG2) layer = or (layer, collaborationVisibility()); } return layer; }
There's been numerous performance optimizations made to CmSym, which has caused a number of API-changes.
Because components on a sym node are limited, sequences are more efficient than maps both speed wise and storage wise. A number of breaking changes have been made so now we instead store components as a sequence field in SymNode
.
Instead of asking for:
featureProvider("mesh");
You use:
featureProvider(symFeature.mesh);
In this case it's simply better to use:
public SymComponent meshProvider(SymNode this) : inline {
This change is also made for performance reasons.
It's been very common for developers to simply add reps()
or reps3D()
to all their nodes. But it's undesirable to do so because it will implicitly create a LOD for all details, which have negative performance impacts.
Therefore you now have to explicitly ask for the exact details you want:
reps2D(#super) reps3D(#medium, #high)
This what the previous settings would produce:
reps2D() -> reps2D(#low, #medium, #high, #super) reps3D() -> reps3D(#low, #medium, #high, #super) reps() -> reps(#low, #medium, #high, #super)
(This also excludes the "base" detail level, but it should only exist in Model Lab so you should be able to ignore it).
Note that there's no support for any other 2D detail level than super.
A number of sym functions that were deprecated in 10.5 have been removed. This predominantly affects SymHandle
methods, such as:
myHandle.setMesh(newMesh);
Which can be replaced with:
symEdit(myHandle) { myHandle.xsetMesh(newMesh); }
or
SymHandle h = sym.beginEditHandle("path.to.handle"); h.xsetMaterial(greenGM); h.endEdit();
or
SymOwnerNode sym = sym(); sym.beginEdit("path.to.handle"); sym.handle("path.to.handle").xsetMesh(newMesh); sym.endEdit();
See the 10.0 to 10.5 migration guide for more information.
Do note that previously, handle.setMaterial()
used to be able to set the material for the entire model when loaded, but now each node on the model has its own material that blocks xsetMaterial()
from being able to set the material. Now it’s required to use xsetGroupMaterial()
to set the material for a handle of an imported sym file.
Instead of referring to components with string keys:
node.hasComponent("symReps"); node.getComponent("symReps"); node.removeComponent("symReps");
We now use identifiers:
node.hasComponent(symReps); node.getComponent(symReps); node.removeComponent(symReps);
All SymComponent
classes have their own entry in the symComponentId
:
public enum symComponentId { /** * An invalid component id, used for deprecated components. */ invalidSymComponent = 0; /** * All valid components. */ symGMaterial = 1; symGfx = 2; symMesh = 3; symProps = 4; symReps = 5; ...
Sometimes you'll get a name clash where symReps
can either refer to the enum or a method:
public void doStuff(SymNode this) { hasComponent(symReps); }
c:\CetDev\10.5git\base\cm\format\cmsym\component\test\test_components.cm(144, 26): no function hasComponent(SymReps (symReps(this, false)))
In which case you can explicitly refer to the enum entry like this:
public void doStuff(SymNode this) { hasComponent(symComponentId.symReps); }
This change was introduced for performance reasons.
If you were previously using:
prepareForEdit(h); h.doStuff();
to update components of a handle, it won't work now and you should use a symEdit
block instead.
Due to changes in sym validation we no longer construct a PathTrie
which points out the executed programs. Instead the executed programs are returned directly:
/** * Sym validation info. */ public class SymValidationInfo { /** * Rep. */ private SymRep rep : public readable; /** * Executed programs. */ private SymProgLazyExecEnv[] executedProgs : public readable;
public class SymProgLazyExecEnv { public SymExecEnv env; public SymProg prog; public SymProgs progs; public int depth; public int order; public constructor auto();
This was also made to minimize performance overhead.
Old: public void dcCollectExtRefKeys(DsProductType prd, DataCatalog catalog, str->str{} used, str{} visited); New: public void dcCollectExtRefKeys(DsProductType prd, DataCatalog catalog, str->str{} used); Old: public DcMaterialToolBoxSubWindow::constructor(Window parent, str key, str label=null, bool showHelp=true, str helpText=null, bool noButtonMode=false, int rightCaptionIndent=0, pointI pos=(0, 0), function(SubWindow c) callback=null, SrcRef src=#:src); New: public DcMaterialToolBoxSubWindow::constructor(Window parent, str key, DcDBBuilderSpreadsheet spreadsheet, str label=null, bool showHelp=true, bool noButtonMode=false, int rightCaptionIndent=0, pointI pos=(0, 0), function(SubWindow) callback=null, FrameStyle frameStyle= dsRoundedFrame(dsDialogLightBackgroundBrush), Brush brush=dsDialogDarkBackgroundBrush, DsGridLayoutHelper parentLayoutHelper=null, str helpText=null, str onlineLink=dcOnlineHelpLink("general-commoncomponents", "FindReplace"), SrcRef src=#:src);
private void custom.dataCatalog.builder._internalUndoCB(Control con); private void custom.dataCatalog.builder._internalRedoCB(Control con); public DsGradientButton DcMenuSubWindow::undoBtn; public DsGradientButton DcMenuSubWindow::redoBtn; public class custom.dataCatalog.builder.publish.DcCheckBoxCellStyle public const int custom.dataCatalog.builder.publish.dcCheckBoxSize = 13; extend public void DcDBBuilderGeometryCard::editExtRefKey(); public class DcEditExtRefKeyWindow; public class DcEditOptionWindow; public class DcEditPrdExternalRefKeys; public DsButton DcExternRefWindow::editExtRefKeyBtn; extend public void DcModularCard::buildInfoSection(str helpText); extend public void DcModularCard::buildExtraButton(str buttonKey); public REDShape DcPreviewSnapperREDView3D::ambientLight; public REDShape DcPreviewSnapperREDView3D::cameraLight; public REDShape DcPreviewSnapperREDView3D::distantLight; extend public REDShape[] DcPreviewSnapperREDView3D::allLights(); extend public void DcPreviewSnapperREDView3D::initLights(); extend public void DcPreviewSnapperREDView3D::updateLights(); extend public void DcProductListSubWindow::selectProduct(str productCode); public DcFindReplaceSubWindow DcDBBuilderEditMaterialsCard::findReplaceSub; public DsButtonDropDownTreeView DcDBBuilderEditMaterialsCard::visibleColumnsBtn; public DsGridLayoutHelper DcDBBuilderEditMaterialsCard::layoutHelper; extend public DcDBBuilderEditMaterialsCard DcDBBuilderEditMaterialsCard::card(); extend public DataCatalog DcDBBuilderEditMaterialsCard::catalog(); extend public void DcDBBuilderEditMaterialsCard::populateVisibleColumnsDropDown(); public void DcDBBuilderEditMaterialsCard::setSize(sizeI s); private void removeInvalidProductReferencesFromProductLevel(ProductLevel cur, ProductLevel owner, (str{}) levelsUpdate, int[] currentPath, str prdCat); public class DcProductListTreeViewCopyDragAnimation; public class DcTableOfContentsCopyDragAnimation; extend public void DcDBBuilderEditProductsCard::setProductCatalogFilter(str prodCatCode); public str DcDBBuilderProductsSS::prodCatCode; public DsButtonDropDownTreeView DcProductsToolboxSubWindow::showHideDD; extend public DcDBBuilderEditProductsCard DcProductsToolboxSubWindow::card(); extend public DataCatalog DcProductsToolboxSubWindow::catalog(); extend public void DcProductsToolboxSubWindow::populateShowHideDD() public str PrdIndTagCategoryCell::getData(int x, int y); extend private void PrdCategoryCell::getSubData(DsClassificationRefType ref, str{} res, str key); public DsButton DcTableOfContentsSubWindow::expandAllBtn public DsButton DcTableOfContentsSubWindowcloseAllBtn; public DsButton DcTableOfContentsSubWindow::addLevelBtn; public DsButton DcTableOfContentsSubWindow::addSubLevelBtn; public DsButton DcTableOfContentsSubWindow::toolboxCreatorBtn; public DsButton DcTableOfContentsSubWindow::refreshBtn; public DcTableOfContentsSubWindow::DsGridLayoutHelper layoutHelper; extend public void DcTableOfContentsSubWindow::updateActivation(); public DsButton DcTableOfContentToolboxSubWindow::expandAllBtn; public DsButton DcTableOfContentToolboxSubWindow::closeAllBtn; public DsButton DcTableOfContentToolboxSubWindow::addLevelBtn; public DsButton DcTableOfContentToolboxSubWindow::addSubLevelBtn; public DsButton DcTableOfContentToolboxSubWindow::refreshBtn; public DsGridLayoutHelper DcTableOfContentToolboxSubWindow::layoutHelper;
Notes:
DsCheckBoxCellStyle
can be used instead of DcCheckBoxCellStyle
.Old: public class DcMaterialReferenceValidationEnv1; New: public class DcMaterialReferenceValidationEnv;
The nurb field in DwgSpline
now refers to cm.geometry.brep.BrepBSplineCurve
instead of ANurbsCurve
.
The export methods in Snapper
has changed arguments.
The dwg import dialog has been overhauled, in that process changes has been made to both functionality of the dialog and it's interface.
Settings have generally changed from using last applied from/to coresettings to storing the DwgSettingsEnv
in each DwgSnapper
and using those settings on all modifications from the import dialog.
Presets have been introduced and you can register presets via this function:
/* * Register predefined dwg setting. */ public void regPredefinedDwgSetting(DwgSettingsEnv env, bool replace=false) {
The ExportPaperDwgDialog
class has been removed entirely since papers now can be exported from the ExportDwgDialog
. When exporting to dwg the user now has the possibility to export 2D-view, 3D-view and/or Papers from paper view (current or all).
Due to these changes, some methods have been removed and some have been changed.
These two methods in Snapper
now have one single argument. This is to facilitate the need for more arguments now and in the future. The export()
method is the method to override in case you want non-default dwg-export behaviour.
/** * Export snapper. */ extend public ExportData export(SnapperExportEnv env) { return stdSnapperExport(env); } /** * Export graphical snapper. */ extend public ExportData systemExport(SnapperExportEnv env) { if (hasGraphicalSpecial) return stdSnapperExport(env); else return export(env); }
All the old arguments are contained within the SnapperExportEnv
. New is the LayerSet
which is used when using ViewMode filtered dwg export. If possible filter your snapper graphics using this filter to avoid returning unnecessary data. The SnapperExportEnv
extends CorePropObj
to facilitate the need for more arguments in the future.
/** * Snapper export env. */ public class SnapperExportEnv extends CorePropObj { /** * Export 2D graphics. */ public bool twoDim; /** * Export 3D graphics. */ public bool threeDim; /** * Export item tags. */ public bool itemTags; /** * The wanted detail of the exported graphics. */ public detailLevel detail; /** * The wanted layer of the export. */ public LayerSet layer : copy=reference; /** * Create a new Snapper export env. */ public constructor(bool twoDim=true, bool threeDim=true, bool itemTags=true, detailLevel detail=detailLevel.super, LayerSet layer=normalLayerSet) { this.twoDim = twoDim; this.threeDim = threeDim; this.itemTags = itemTags; this.detail = detail; this.layer = layer; } }
The following public functions have been removed entirely
public void userDwgPaperExport(Window app, Space space, bool initVisible=true, bool applyAndClose=false) public void userPaperDwgExportToTarget(Window app, Space space, bool initVisible=true, bool applyAndClose=false, Url url=null)
Both could be replaced by the functions
public void userDwgExport(Window app, Space space, bool initVisible=true, bool applyAndClose=false) public void userDwgExportToTarget(Window app, Space space, bool initVisible=true, bool applyAndClose=false, Url url=null)
The constructor()
has changed
public constructor(Space mainSpace, PaperSpace[] paperSpaces=null, bool export2D=true, bool export3D=true, ExportFilterBar exportFilter=null)
Previously it only took a Space
as an argument and now a Space
and a seq of PaperSpace(s)
. Any of them can be null
. If you only want to export papers then only pass in PaperSpace
objects. 2D and 3D only applies to 'Space'.
Also due to this change, the following methods in DwgExporter
now takes a Space
as an argument.
extend public void collectSnappers(Space s, SnapperFilter filter=null) extend public rect getViewBound(Space s)
/** * Set env settings. */ extend public void setEnvSettings() {
Has been replaced with:
/** * Apply settings from env. */ extend public void applySettings(DwgSettingsEnv env) {
The case insensitive sort methods, isort()
and isorted()
have been removed for non-string types.
A new colored tag view mode has been added to core and the code can be found in cm.core.partTag.coloredTagViewMode.cm. The colored tag view mode is essentially another way to visualize the tag color of tagged snappers, where the 2D fills of tagged snappers are overridden with the corresponding tag colors.
For customization teams that have similar view modes and plan to migrate to the new colored tag view mode, just replace existing view modes with the new colored tag view mode. Please also remember to replace any references to the old view mode keys with the new colored tag view mode key.
We have changed a few functions in the print API (cm.std.print) so that you need to explicitly provide the "correct" world. "Correct" world, in this case, means the world that the function in question wants to operate on. In many cases, we used to rely on session.mainWorld(..)
. Usually, this works fine but it is more robust to provide the correct world if we have data that refers to it. For instance, you may use methods found in Session
, such as worldFromWindow(..)
or worldFromAppWindow(..)
.
The method signature of PropObj::pushProp()
has changed.
Old: extend public bool pushProp(str key, PropObj z, Object env=null, StrBuf error=null) { New: extend public bool pushProp(str key, PropObj z, Object env=null, StrBuf error=null, PushPropsEnv receiverEnv=null, PushPropsEnv pusherEnv=null) {
Support for Singularity
candidates has been added to ToolAnimationG2
. This means a variety of new methods in ToolAnimationG2
and Singularity
to mirror those related to Snapper
and Vessel
candidate picking. To turn on Singularity
candidate picking in a ToolAnimationG2
-derived animation, override singularityCandidateSearch()
. If your animation is not meant to handle singularity candidates, the animation itself does not require a migration.
Support for picking candidates through XClipWormhole
has also been added (using ThruWormholeAnimationCandidatePicker
will do this by default). These changes resulted in the following interface changes in FuzzyAnimationHeapCandidatePicker
.
extend public void pick(SnapperFilter snapperFilter=null, VesselFilter vesselFilter=null) {
Has been changed to
extend public void pick(SnapperFilter snapperFilter=null, VesselFilter vesselFilter=null, SingularityFilter singularityFilter=null) {
And
extend public void addPicksToHeap(Object[] picks, SnapperFilter snapperFilter, VesselFilter vesselFilter, bool loose) {
Has been changed to
extend public void addPicksToHeap(Object[] picks, SnapperFilter snapperFilter, VesselFilter vesselFilter, SingularityFilter singularityFilter, bool loose, Transform t=null) {
Elevation Arrows now works with Favorites, Copy/Paste and Collaboration. Prior to the update, the Space
was reset and any added Snapper(s)
to the ElevSpace
was not coming with the Favorite/Paste/Collaboration load.
To ensure proper behavior any Customization code that uses Elevation Arrow and ElevSpace
should consider removing special code that circumvents the previous limitations and that may make the update not work as intended.
PHBodyInsertAnimationG2
PHBodyWidthAdjustingAnimationG2
PlacingMultiplePHBodyAnimationG2
ShelvingPropertyStretchAnimation
(superStretch)ShelvingSystemInfo.positionShelving()
wrongfully offset the first upright by its own width.PHBody.afterShelvingInsert()
is called for every PHBody
after the shelving has been inserted. This allows for any adjustments needed to be done after the insert. The calls to PHBody.afterShelvingInsert()
is done in the same Undo step as the insertion.ignore modify notice
and/or stream=null
are automatically discarded to prevent them from being part of the soul key.#stream_null
are automatically discarded to prevent them from being part of the soul key.LOPosition
flags front
, inner
and back
into account.LOPosition
according to compareLOPosition()
function. The str->tuple maps only sorted on point.toS
.Added symbol and text categories for all labs categories.
Added warp space domain registration for LabsElevationSpace
on abstract.labs init to give new viewports visibility to those views.
acceptScheme()
has been overridden on the following classes:
LabsWorktop
LabsRackContent
LabsRackFront
LabsSideSplash
Other classes that were previously overridden:
LabsSink
LabsTap
LabsElevationAutoInsertEnv
needs class types passed in as argument rather than an instantiated LabsElevationArrow
object.
Previous constructor cm.abstract.labs.LabsElevationAutoInsertEnv
:
/** * Creation. */ public constructor(LabsElevationArrow frontElev, LabsElevationArrow sideElev, LabsElevationArrow worktopElev, LabsElevationArrow rightSideElev=null, LabsElevationArrow backElev=null) { elevationAutoInsert(frontElev, sideElev, worktopElev, rightSideElev, backElev); }
New constructor cm.abstract.labs.LabsElevationAutoInsertEnv
:
/** * Creation. */ public constructor(Class frontElev, Class leftElev, Class worktopElev, Class rightElev=null, Class backElev=null) { if (frontElev.extends() in ElevArrow) this.frontElev = frontElev; if (leftElev.extends() in ElevArrow) this.leftElev = leftElev; if (worktopElev.extends() in ElevArrow) this.worktopElev = worktopElev; if (rightElev.extends() in ElevArrow) this.rightElev = rightElev; if (backElev.extends() in ElevArrow) this.backElev = backElev; elevationAutoInsert(); }
In addition to this, you can leverage the arrowArgs()
on LabsRectRack
to set fields post-construction as needed. (Don't forget your PropDef
).
/** * Arrow Args for auto generated arrows. */ extend public str->Object arrowArgs(str dir=null) { return null; }
OfficeMaterialSelection
to actually use the default size if none is provided.PanelFrame
.animationTrySnap()
on worksurface actually return whether it was successful or not, previously it would always return false.PanelFrame
were inset by one inch on each side. This was to visually offset the connector graphics since there was code in place to have them functionally behave as if they weren't inset at all.PanelFrame
, one would have to either program around this offset by including the one inch in the connectsX()
locations for any PanelJunctions
, or override the initialLeftSnap()
, initialRightSnap()
, updateLRSnaps()
, and the connectOffset()
methods.connectsX()
method accordingly to no longer use the one inch offset. There is load code on PanelFrame
to adjust old drawings to make sure no connections are lost/broken on load.initializeWorksurface()
OfficeCabinet
now uses visiblePosition()
instead of visible3DPosition()
for adjusting connector graphics. The visible3DPosition()
and visible2DPosition()
methods call visiblePosition()
by default.PickSkinAnimation
now shows the discard property after a skin has been selected.WorksurfaceDragAnimation
has been updated to reflect updates to DragAnimation
.WorksurfaceInsertAnimationG2:update()
has been updated to reflect past updates to InsertAnimationG2:update()
.Coming with 11.0, Categories registered at the Abstract Office level have been drastically changed. This was done with feedback from the F5 and past feedback about categories in general. As such, code updates will be required as part of these changes.
To properly migrate/update to the new categories, a few things need to be done.
First, any place where category symbols were explicitly called out need to be updated. This includes view modes, layers, addSystemCategoriesTo()
method on Snapper
, systemCategories()
method on ItemTag
, etc.
Second, consider updating/removing extension specific categories in your custom packages. The new categories cover most of the common office product types so chances are there will be overlap with your current categories.
Because users can manually apply categories to snappers and item tags and can make custom view modes with them, to migrate these over, a migration map must be registered. This has already been done for Abstract Office, but if you are going to map your own categories over to new ones or ones in Abstract Office, you will also need to do this. An example of this is shown below and is taken from Abstract Office.
putCategoryMigratoryMap(cAOPkg, cF5CatUpdateVer, aoCategoryMigrateMap());
/** * Since some of the old categories are very generalized and the new * sub categories are very specific, we can't accurately map user * applied categories, view modes, or view ports. * * In those cases, we will map the the most general category we can and let * the user adjust to a more specific category. */ public symbol->symbol aoCategoryMigrateMap() { static symbol->symbol cats(); if (!cats.any) { cats.put(#walls, cAOArchWallsCat); cats.put(#panels, cAOPanelsPanelCat); cats.put(#electric, cAOElectricalCat); cats.put(#storage, cAOStorageCat); cats.put(#desking, cAOCasegoodsCat); cats.put(#seating, cAOSeatingCat); cats.put(#worksurfaces, cAOWksfWorksurfaceCat); cats.put(#tables, cAOTablesTableCat); cats.put(#lighting, cAOLightAccessoryCat); cats.put(#legend, cAOLegendsCat); cats.put(#isoviews, cAOElevationCat); // old sub categories cats.put(#panelAnnotation, cAOPanelsPanelTxt); cats.put(#panelSym, cAOPanelsPanelSym); cats.put(#tableText, cAOTablesTableTxt); cats.put(#wsText, cAOWksfWorksurfaceTxt); cats.put(#wsSym, cAOWksfWorksurfaceSym); cats.put(#ohStorage, cAOStorageUpperCat); cats.put(#ohStorageTxt, cAOStorageUpperTxt); cats.put(#ohStorageSym, cAOStorageUpperSym); cats.put(#storageSym, cAOStorageLowerSym); cats.put(#storageText, cAOStorageLowerTxt); } return cats; }
The map is defined as old category to new category (symbol->symbol). With this map, you then register it to a global migrator by using the function putCategoryMigratoryMap()
. This function takes in symbol that represents the package the categories were registered with (for example cm.abstract.office), a version when the migration is happening (so in this case 11.0.0), and then the map of old to new categories.
/** * Package symbol to map of old category and new category. */ private CategoryMigrator _catMigrator : keep; public CategoryMigrator categoryMigrator() { if (!_catMigrator) init _catMigrator(); return _catMigrator; } /** * Put a migratory map (old category, new category) for a specific package. */ public void putCategoryMigratoryMap(symbol pkg, version v, symbol->symbol pairs) { categoryMigrator().putMigrator(pkg, v, pairs); } /** * Put a migratory map (old category, new category) for a specific package. */ extend public void putMigrator(symbol pkg, version v, symbol->symbol pairs) { version->symbol->symbol verMap = versionMigrateMap.get(pkg); if (verMap) { verMap.put(v, pairs); } else { version->symbol->symbol temp(); temp.put(v, pairs); versionMigrateMap.put(pkg, temp); } }
This registered map will be used when snappers, item tags, view ports, elevations, and custom view modes load to 11.0 to migrate their user applied categories correctly. This happens during loaded1()
of these objects. The migrator and its code can be found in cm/core/category/categoryMigrator.cm.
public void loaded1(ObjectFormatter formatter, LoadFailInfo failInfo) { super(formatter, failInfo); if (dbg_traceSnapperEvents) ptrace(); if (dbg_traceSnapperEvWPln) pln("EV: ", this, ".loaded"); #if (trackSnapperHistory) history(", ld1"); initVessels(); if (pkgVersion(#"core", formatter) < version(11, 0, 0)) { migrateCategories(formatter); } } /** * Manually migrate any category failures after the migrator has mad an initial pass. */ extend public void migrateCategoryFailures(symbol{} failures) { // Subclass responsiblity! }
How this works is that when the first object tries to migrate, all registered migration maps will be consolidated down based on their versions. For example, if the current version of Fika is 11.5 and a 10.5 drawing is loaded, migration for 11.0 and 11.5 will be checked and consolidated down for each package. If in 11.0, category A changed to category B, and in 11.5 category B changed to category C, the migrator will have a migrate A to C for all objects whose class is under custom.fika. Categories from core/abstracts will always be migrated after ones for a custom. This can also be handled at the snapper and item tag levels through the migrateCategories()
method. This is the method that passes the object to the migrator to be processed. There is also the migrateCategoryFailures()
method that gets called after the first pass of migration where extension specific categories should have been migrated. Here you can change how categories from core/abstracts get migrated.
Alt-i was specifically inconsistent in 10.5 if a file was saved as UTF-8 instead of UTF-16 because CmScanner
skipped the byte-order-mark (BOM). This is corrected in 11.0 and some other adjustments to alt-i should make it more consistent and correct.
In 10.5 alt-i sometimes does not move to the target even though a next-error-list was output. This has been fixed as well in 11.0.
Motivation:
PropDef.adjusted()
is extremely central to all customization code and we need to keep a thorough lookout for any trouble. If any trouble arises, the following debug-tools have been prepared:
adjusted()
remains in PropDef as deprecated_adjusted()
.private const bool dbg_trace_put = true;
PropObj
has a deprecated_put()
PropObj
has a compare_put()
which runs both new and old versions to pinpoint what potentially differsuse cm.props, cm.subset, cm.basic; private class T1 extends PropObj { public props { double "w" v=0.2 : domain=DoubleEnum(0.2, 0.4); distance "d" v=0.3 : domain=DistanceEnum(0.3, 0.5); distance "e" v=distance(0.3) : domain=DistanceEnum(0.3, 0.5); } } { T1 z(); pln(#z."w"); z."w" = 1; // uses the new PropDef adjusted which allows us to widen Int(1) -> double PropDef field pln(#z."w"); pln(#z."w".class); } output: z."w"=0.2 z."w"=1 z."w".class=Double { T1 z(); pln(#z."w"); z.deprecated_put("w", 1); // same behavior as in 10.5 pln(#z."w"); pln(#z."w".class); } output: z."w"=0.2 PropDef(double w [ reg boxClass=Double]).depr_adj() null value or wrong boxClass double=1.Int, pType.boxClass=Double z."w"=0.2 z."w".class=Double
Upgraded error reporting
{ T1 z(); pln(#z."w"); z."w" = "ddd"; // "w" is a double field } output: z."w"=0.2 PropDef(double w [ reg boxClass=Double]).adjusted() value type mismatch: double=ddd.Str
Extended tracing and compare put
cm.props propDef.cm private const bool dbg_trace_put = true;
{ T1 z(); pln(#z."w"); z."w" = 1; pln(z.compare_put("w", "dd")); } output: z."w"=0.2 compare_put: new PropDef(double w [ reg boxClass=Double]).adjusted() value type mismatch: double=dd.Str old PropDef(double w [ reg boxClass=Double]).depr_adj() null value or wrong boxClass double=dd.Str, pType.boxClass=Double new=dd OLD=dd <dd, dd>
{ T1 z(); pln(#z."w"); z."w" = 1; pln(z.compare_put("w", Byte(2))); } output: z."w"=0.2 compare_put: new old PropDef(double w [ reg boxClass=Double]).depr_adj() null value or wrong boxClass double=2.Byte, pType.boxClass=Double new=2 OLD=2 <2, 2>
If you wish to add your own widening conversions to PropDef.put()
, please contact dev support.
Supported widening conversions
private Object angleF_sangleF_widener(Object z) private Object angleF_sangleF_widener(Object z) private Object angle_orientation_widener(Object z) private Object angle_orientation_widener(Object z) private Object angle_sangle_widener(Object z) private Object angle_sangle_widener(Object z) private Object byte_double_widener(Object z) private Object byte_double_widener(Object z) private Object byte_float_widener(Object z) private Object byte_float_widener(Object z) private Object byte_int16_widener(Object z) private Object byte_int16_widener(Object z) private Object byte_int64_widener(Object z) private Object byte_int64_widener(Object z) private Object byte_int_widener(Object z) private Object byte_int_widener(Object z) private Object byte_nat64_widener(Object z) private Object byte_nat64_widener(Object z) private Object byte_nat_widener(Object z) private Object byte_nat_widener(Object z) private Object byte_word_widener(Object z) private Object byte_word_widener(Object z) private Object color_colorF_widener(Object z) private Object color_colorF_widener(Object z) private Object distance_double_widener(Object z) private Object distance_double_widener(Object z) private Object float_double_widener(Object z) private Object float_double_widener(Object z) private Object int16_double_widener(Object z) private Object int16_double_widener(Object z) private Object int16_float_widener(Object z) private Object int16_float_widener(Object z) private Object int16_int64_widener(Object z) private Object int16_int64_widener(Object z) private Object int16_int_widener(Object z) private Object int16_int_widener(Object z) private Object int16_nat64_widener(Object z) private Object int16_nat64_widener(Object z) private Object int64_double_widener(Object z) private Object int64_double_widener(Object z) private Object int8_double_widener(Object z) private Object int8_double_widener(Object z) private Object int8_float_widener(Object z) private Object int8_float_widener(Object z) private Object int8_int16_widener(Object z) private Object int8_int16_widener(Object z) private Object int8_int64_widener(Object z) private Object int8_int64_widener(Object z) private Object int8_int_widener(Object z) private Object int8_int_widener(Object z) private Object int8_nat64_widener(Object z) private Object int8_nat64_widener(Object z) private Object int_double_widener(Object z) private Object int_double_widener(Object z) private Object int_float_widener(Object z) private Object int_float_widener(Object z) private Object int_int64_widener(Object z) private Object int_int64_widener(Object z) private Object int_nat64_widener(Object z) private Object int_nat64_widener(Object z) private Object nat_double_widener(Object z) private Object nat_double_widener(Object z) private Object nat_float_widener(Object z) private Object nat_float_widener(Object z) private Object nat_int64_widener(Object z) private Object nat_int64_widener(Object z) private Object nat_nat64_widener(Object z) private Object nat_nat64_widener(Object z) private Object point2D_rect_widener(Object z) private Object point2D_rect_widener(Object z) private Object point2D_size2D_widener(Object z) private Object point2D_size2D_widener(Object z) private Object pointI_point2D_widener(Object z) private Object pointI_point2D_widener(Object z) private Object pointI_rect_widener(Object z) private Object pointI_rect_widener(Object z) private Object pointI_size2D_widener(Object z) private Object pointI_size2D_widener(Object z) private Object point_colorF_widener(Object z) private Object point_colorF_widener(Object z) private Object point_color_widener(Object z) private Object point_color_widener(Object z) private Object point_version_widener(Object z) private Object point_version_widener(Object z) private Object rangeI_range_widener(Object z) private Object rangeI_range_widener(Object z) private Object size2D_rect_widener(Object z) private Object size2D_rect_widener(Object z) private Object word_double_widener(Object z) private Object word_double_widener(Object z) private Object word_float_widener(Object z) private Object word_float_widener(Object z) private Object word_int64_widener(Object z) private Object word_int64_widener(Object z) private Object word_int_widener(Object z) private Object word_int_widener(Object z) private Object word_nat64_widener(Object z) private Object word_nat64_widener(Object z) private Object word_nat_widener(Object z) private Object word_nat_widener(Object z)
In 11.0 its a lot easier to get started using background reports. Now there is a single interface in cet/runtime/errorlogger.cm. To send an background report simply call this function with the data you want to include in the report.
New for 11.0 is that files now can be added to the report using the files field.
/** * Log error. * * Origin is an optional reference to issue origin. */ public void logError(str message=null, Exception exception=null, CallStack stack=null, StrBuf logOutput=null, SrcRef origin=null, SrcRef loggedAt=#:src, Url[] files=null) { errorLogger.logError(..); }
In 11.0, all built in string type (str) comparison methods have been changed to be locale-independent to ensure deterministic behavior. This includes compare()
, icompare()
, gt()
, lt()
, ge()
, le()
, sort()
, isort()
, >, >=, <, <=, and sorted maps with str key types.
In previous versions, certain low level drivers were overriding the global locale which resulted in unpredictable behaviors with CET, usually manifesting in issues with displaying the correct $RS value or crashes in worst cases. This change means that the C locale environment variable (LC_ALL) will now be ignored.
In practical scenarios, this should not affect general behavior such as sorting or localization, as CM has been using the default LC_ALL=C
locale, and most UI in CET should be handled transparently with our localization wrappers. However, testing should still be done to ensure there are no undesirable side effects.
We have provided a detector for any such methods that may be affected by the changes above. Simply run the code below, and evaluate if each warning need to be fixed (see next sections).
{ enableLocaleStrCompareWarnings(enable=true, warnings=true); cm.runtime.util.qmegaCAB("custom.extensionName"); }
We have also provided versions of the methods above, prefixed with lc_
, which will behave the same as older versions of CM, including lc_compare()
, lc_icompare()
, lc_gt()
, lc_lt()
, lc_ge()
, lc_le()
, lc_sort()
, lc_isort()
. These methods would respect the C Locale, however we would recommend to only use them if you are sure you need to.
For sorted maps, you can fix by setting a custom compare function:
{ sorted str->int test = ["dd"->3, "ee"->4]; test.setCompare(function lc_compare3); public int lc_compare3(str a, str b, Object env) { return lc_compare(a, b); } }
Simply add // !lc
to the end of the line of code.
We have made some changes to Line Styles in 11.0 This affects how they look in:
Both line thickness and the look of stippled lines (dot, dash, dash-dot etc) are affected. The default thickness of solid lines should look the same as before.
Note that this will affect any PDF DIFF Tests with references made before 11.0. If you have any references with lines for PDF Diff Tests made before 11.0, the different line styles will cause the diff test to fail if run in 11.0. You will need to make new references in 11.0 for those tests.
You may find more information and some comparison images on this page.
selected()
now has a CoreObject
owner passed through as needed./** * Selected. * From componentVessel in space OR from pickSurface in view. * Return true if taken care of. */ extend public bool selected(View view, WindowViewMouseInfo mi, PickSurface3D surface, CoreObject owner=null) { /** Subclass */ return false; }
/** * Update Components. */ public void updateComponents() { update(); super(..); } /** * Update */ extend public void update() { /** Subclass */ }
CoreObject
now has:/** * Update Components. */ extend public void updateComponents() { for (c in components()) c.updateComponents(); }
/** * Rotate component on insert. */ extend public Orientation componentInsertRotation(Component component, Animation insertAnimation) { return null; }
Note: Nothing inherently calling this. You still need to manually invoke this as needed.
For a more complete guide/explanation, please refer to this page We have shrunk the default calculations that are visible to these 7:
We have made abstract dataSymbol columns not visible by default so you do not get 15 visible columns for turning on an extension with dataSymbol.
DsPRdAreaColumn
DsPrdMeasurementColumn
DsFeatureDescPartColumn
DsPrdMeasurementColumn
DsPrdMeasurementColumn
DsPackageCountColumn
DsPreviewColumn
DsPricelistColumn
DsPrdSKUColumn
DsVendorNameColumn
DsPrdVolumeColumn
DsPrdWeightColumn
DsPrdMeasurementColumn
Instead of showing every registered column set to initially visible, we now set a limit of 10 columns to show in the calculation view. These will be determined by votes cast by each extension. The 10 columns with the most votes will show.
These votes should be placed in the extension start. They will be cast once the extension is turned on (for lazy extensions, this means when it is selected in toolbox).
Voting for columns is done like this:
upvotePartColumnVisibility(absUpchargePartColumn.key); upvotePartColumnVisibility(absSourcePartColumn.key);
For tag columns, there are no public PartColumn classes so you have to specify the key like this:
upvotePartColumnVisibility("#cm.core;TAG1")
You can find core/abstract part columns in the following places:
If the feature descriptions are empty in the calculation dialog, do check your overridden DsPart
class's infoTrees()
method. When constructing a DsOptionInfoTree
, pass in the groupDescription
argument. As that is what will be shown in the calculation dialog.
Version 11.0 introduces a new inspection tool for users to view categories, tags, level, collaboration section, and other information associated with Snapper(s)
and ItemTag(s)
. In order to generically obtain the tag text of an ItemTag
(for identification purposes in the dialog), the following method has been added to ItemTag
:
/** * Tag Text. */ extend public str tagText() { if (info and !info.tagText.emptyOrOnlyWhiteSpace) return info.tagText; return $noTagTextFoundFor # " " # toS; }
If you implement an ItemTag
that does not store its text in its ItemTagInfo
, it is imperative that you override tagText()
to point towards either the actual displayed text or some other text that identifies the ItemTag
.
cm.format.json.JsonInt
now stores the numeric value as int64 instead of int. Be careful when calling JsonInt.int()
as the returned value will be incorrect if the real value is not between minInt
and maxInt
.
// Max int value. public const int maxInt = 2147483647; // Min int value. public const int minInt = (-2147483647 - 1);
The syntax soulModify
and quickSoulModify
now supports nesting. The temporarliy spawned soul copy gets replaced by a pure soul at the end of the outermost soulModify
/quickSoulModify
block.
SymNode(s)
now hold a mask of all components both on the node and everything below. This means we can now iterate efficiently over the structure if we're searching for something specific.
For example this code would in 10.5 always visit the whole graph, but in 11.0 it will instantly abort if there's no mesh below a node:
for (node in root, filter=SymNodeMeshFilter()) { ... }
Most filters (with the exception of searching for specific node ids or leafs) are now efficient. For example if you would like to visit nodes that contain geometry, with a specific rep and that is tagged you can do this:
SymNodeFilter f = and(SymNodeRepFilter(rep), SymNodeGeometryFilter(), SymNodeComponentFilter(symTags)); for (node in root, filter=f) { ... }
Internally this is used in many places to speed up the handling of syms, and should be used if possible.
We have corrected the perpendicular()
function for orientation and orientationF. Previously it did not return a vector that was orthogonal against the direction/normal vector.
We have upgraded props scheme with a new look together with the new selection tool dialog(Tools > Advanced Selection ...). Most of the changes for props scheme are related to UI elements.
All related files to PropsScheme
has been moved into cm.core.propsScheme directory.
More information can be found in PropsScheme Migration
The parameters used to control stretching behavior for CmSym models have been changed. Previously the stretch operation took two parameters as input:
stretchingEP
(bool)wantedLength
(double)This works well for most scenarios but if you change the stretchingEP
parameter between different stretch operations you were forced to keep track of how much you stretched in each direction by yourself. To overcome this we have replaced the stretchingEP
param with a new param called spOffset
. This means that we now use the following two parameters to control the stretch operation:
spOffset
(double)wantedLength
(double)This means that we from now on always "right stretch" first (stretch the end point of the measure) and then adjust everything stretched by applying an offset - spOffset
. If spOffset
if positive "everything" will move in the sp -> ep direction. If spOffset
is negative "everything" will move in the ep -> sp direction. This gives us two benefits:
Note A: Old CmSym files with stretching behavior will continue to function and you may still change the stretchingEP
param for these old CmSym files.
Note B: If you import an old CmSym file, with stretching already defined, to Model Lab the old stretch programs will be translated to the new spOffset
approach. So if you for some reason want to change an old CmSym model with stretch beavior already defined you must adapt the new way of controlling the stretch operation.
Keys prefixed with "_" are now reserved for internal use in SymProps
only. Any internal key, like localBound
, will now use _localBound
instead. If you use the props API make sure you don't use the "_" prefix.
The hasGeometry
flag in SymProps
has been removed (corresponding to the symGeometryKey
id). It has been replaced with matching against the component mask. The call SymNode.hasGeometry(descend=true)
is still fast, and the prop can simply be ignored.
In CET 10.5 and older versions, we used to call rebuildAllToolboxCards()
when the main app window got resize and resizeEnd. These calls (of course) produce a lot of slow response and flickering, so they have been removed. This means that your custom toolbox cards will no longer get rebuilt on app window resize, and there is no reason they should have to. However, if you really need this, please contact developer support!
In order to convert the legacy viewports to XClip view clips, four new methods has been added to the Viewport2D
class:
public XClipWormholeSnapper2D createXClipFromViewport() { ... } public XClipWormholeSnapper2D createXClipFromWormholeCollapsed(Space space = null) { ... } public void copyConfiguration(XClipWormholeSnapper2D wh) { ... } public void createCompanionsFromViewport(XClipWormholeSnapper2D wh, XClipWormholeCompanionSnapper[] companions) { ... }
The first two methods generates a XClipWormholeSnapper2D
object from the current ViewportSnapper2D
instance and can be overridden in case your extended Viewport2D
requires some intricate conversion logic.
If your viewport has some additional configuration, this can be converted by simply overriding the copyConfiguration()
method, which is called in both viewport conversion methods. Let's look at the base method:
/** * Copy configuration. */ extend public void copyConfiguration(XClipWormholeSnapper wh) { if (!wh.settings) return; if (blackAndWhite) wh."whBlackWhite" = true; if (ViewMode vm = getRegisteredViewMode(this.?viewModeKey.str)) { wh.setViewMode(vm); } else { wh.setViewMode(ViewMode("cm.core.visibility","newViewModeName", viewModeLayers)); } if (ViewContentFilter filter = viewContentFilter) { wh.setViewContentFilter(copyContentFilter(filter)); } }
The ViewportSnapper2D
class has a member called blackAndWhite
, indicating whether the viewport should be without colors. This corresponds to the whBlackAndWhite
property of the XClip view clip. The conversion transfers this configuration option to the new view clip in line 3.
In some cases, some of your extended viewport functionality can be abstracted into a companion. If this is the case, the method createCompanionsFromViewport()
can be extended to automatically create and attach companions to the new XClip view clip based on the current ViewportSnapper2D
. Let's look at the implementation of the base method:
/** * Create companions from the give viewport. * XClipWormholeSnapper wh currently unused, still kept since subclass might need it. * XClipWormholeCompanionSnapper[] companions is the list which should be populated with new companions by this method. */ extend public void createCompanionsFromViewport(XClipWormholeSnapper wh, XClipWormholeCompanionSnapper[] companions) { if (!frameType.none) { XClipWormholeFrameCompanionSnapper frame(); frame."frameType" = frameType; frame."lStyle" = usedLineStyle; frame."lineWidth" = lineWidth; frame."lineColor" = lineColor; companions << frame; } if (showScale) { XClipWormholeScaleCompanionSnapper scale(); scale."frame" = !frameType.none; companions << scale; } }
The ViewportSnapper2D
object uses the frametype
member to indicate its frame. In XClip view clips, however, the frame functionality exists in a companion object which is attached to the viewport. So, in the conversion, if the ViewportSnapper2D
instance has a frame, an XClipWormholeFrameCompanion
instance is created, the frame type is set, and the companion gets appended to the companions
list. That list will later be used to attach all companions to the new XClip view clip. The creation of the frame companion is implemented on lines 7-15.
The XClip view clip supports showing contents from other spaces then the main 2D space. If multiple spaces exists in the drawing (e.g. alternatives, elevation views, etc.), the user will see a dropdown option for selecting other spaces than the main 2D space when inserting a new view clip. In order to add your own custom spaces to the list of available spaces you need to add an XClipWarpSpaceDomainEnv
for your type of space.
The code below illustrates how the XClipWarpSpaceDomainEnv
looks for elevation spaces.
public class ElevWarpSpaceDomainEnv extends XClipWarpSpaceDomainEnv { public constructor() { spaceClass = ElevSpace; } /** * Return the name of the space. * if the return string is null the space will not be added. */ public Str spaceName(Space space) { if (space as ElevSpace) { if (space.arrow) { return space.arrow.label(); } } return null; } }
Once your XClipWarpSpaceDomain
subclass has been implemented, it has to be registered in the xclip system. This is done using the global method xclipAddWarpSpaceDomain(XClipWarpSpaceDomain env)
.
xclipAddWarpSpaceDomain(ElevWarpSpaceDomainEnv());
Your specific space might also want a specific XClipSpaceManager
that has some special logic for handling XClip-related events in your space. Refer to XClipSpaceManager
and ElevXClipSpaceManager
for further details on the class implementation. Once your space manager is implemented, connect it to your space by overriding the initXClips()
method in your space.
public class ElevSpace extends Space { ... /** * init Elevation xclip space manager. */ public void initXClips() { if (!xclips) xclips = ElevXClipSpaceManager(this); } ... }
There are currently 2 types of Companions for XClip view clips:
1.Graph additions - Changes the graphic of the view clip snapper, but does not alter the content (e.g. add a frame around the view clip, draw out the used scale of the view clip, etc.).
The Companion connects to the XClip Wormhole using normal connectors. They connect at (0, 0, 0) and shares rotation. This means the XClip Wormhole and the Companions connected have the same local coordinate systems (I.e. 5mm x-axis into the XClip Wormhole is 5mm x-axis into the Companion.
All Companions must inherit from XClipWormholeCompanionSnapper
and the class must be registered using the registerXClipWormholeCompanionClass()
function. When registered the Companion will show up in the same box in the Paperspace Toolbox under the XClipWormhole icon.
To create a Graphical Companion implement as a normal GraphSnapper usingG2() = true
subclassing the base class directly XClipWormholeCompanionSnapper
.
To create an Editor Companion inherit from the XClipWormholeEditor2DCompanionSnapper
class and override the createEditor()
method.
Standard CET Wormhole Companions:
XClipWormholeScaleCompanionSnapper
- Shows the scale of the XClip Wormhole.XClipWormholeFrameCompanionSnapper
- Creates a border around the clipped area in the XClip Wormhole.XClipColumnBalloonCompanion
- Shows and dimensions Column balloons outside edge of XClip Wormhole.XClipWormholeTagCompanionSnapper
- Colors content of XClip Wormhole with tagged Part Tags from chosen Part Tag Category.Starting from version 11.0, it is possible to give graphs a black fill color when using the BlackAndWhite companion. To do this, add a property called blackAndWhiteAllowFill
to your snapper and set it to true. This will fill all graphs in that snapper where the line color is the same as the fill color.
Column balloons are reference balloons for Columns in the drawing. They can be named and are interfacing with the XClip Column Balloon Companion.
If your Extension has Column Balloons it is strongly recommended to subclass the CET standard Column Balloon for future compatibility.
If you have auto papers that previously generated viewports, these will now be automatically converted to view clips. All configuration and functionality of the AbsAPViewport2D
will be transferred to the view clip through a companion called AbsXClipApWormholeSettingsCompanionSnapper
. However, since the conversion is performed by the makePapers()
method, you need to manually add the code line below in your subclass if this method has been overridden. The code below shows how and where the conversion is made in the BasicAPPaperMaker
class.
/** * Create paper(s) from the env. */ public PaperSpace[] makePapers(AbsAPGroupEnv env) { StreamPaper stream(templateUrl); PaperSpace newSpace = stream.load(env.world); if (!newSpace) return null; if (paperGroup) newSpace.group = paperGroup; for (z in newSpace.snappers) { if (developMode) { // Not needed in release. // FIXME: Will be unneeded when StreamPaper is fixed. z.initEntityId(newSpace); } if (z as ImageSnapper) { str fileName = z.originalFilename; Url imUrl; for (im in filesIn(templateUrl, fileName # ".*")) { imUrl = im; break; } z.file = imUrl; z.createGImage(); } z.propDefs; if (PropDef def = z.propDef(cAbsAPPushEnvProp)) { def.put(z, this, env); z.invalidate(dirty2D.rebuild); } if (z as AbsAPViewport2D) z.replaceWithXClip(); // <================ This line converts the viewport } return [newSpace]; }
If you want to create a button for inserting a view clip that automatically modifies the view clip in some fashion (e.g. attaching companions, changing some configuration etc.) you can use the method xclipWormholeSnapperLimb()
. This method has one parameter called configureCallback
which will be invoked once the view clip has been created, providing a straight-forward method of editing your newly created view clip. For instance, the function createCustomXClipLimb
below creates a button which starts the animation for inserting a view clip and automatically attaches an AbsXClipAPWormholeSettingsCompanionSnapper
to each.
use cm.core.xclip; package const symbol pkgXClip = #"cm.core.xclip"; /** * Configure the wormhole however you like */ package void configureWormhole(XClipWormholeSnapper wh) { AbsXClipAPWormholeSettingsCompanionSnapper c(); c.z2m = apViewportZoomMode.group; wh.connectCompanion(c); } /** * Create our own button which lets us configure the wormhole snapper using the method above. */ package ComponentLimb createCustomXClipLimb(LibraryLimb parent, symbol pkg, str key, UIHint hint=null) { return xclipWormholeSnapperLimb(parent, pkg, key, hint, function configureWormhole); }
checkFile
was previously true, but it's now false because of the possibly severe performance penalty of including modification date for a cached request, if it's just going to use the cache anyway.
public SymNode loadSym(Url url, bool lazy=true, bool cache=true, bool checkFile=false) {
In 10.5 eqBox(Str, Str)
and other cases produces incorrect results. eqBox()
now uses the eqBoxedValue()
function which always has produced correct results for all boxed values including strings.
use cm.runtime; { str a = "dd"; str b = "dd"; str c = "d" # "d"; str d = b.copy; pln(#a.eqBox(b)); pln(#a.eqBox(c)); pln(#a.eqBox(d)); pln(#a.eqBoxedValue(b)); pln(#a.eqBoxedValue(c)); pln(#a.eqBoxedValue(d)); } 10.5: a.eqBox(b)=true a.eqBox(c)=false a.eqBox(d)=false a.eqBoxedValue(b)=true a.eqBoxedValue(c)=true a.eqBoxedValue(d)=true 11.0: a.eqBox(b)=true a.eqBox(c)=true a.eqBox(d)=true a.eqBoxedValue(b)=true a.eqBoxedValue(c)=true a.eqBoxedValue(d)=true
All functions in cm.core.calc.articleViewsInSpace.cm now use putAuxillaryObject()
/getAuxillaryObject()
instead of putAuxillary()
/getAuxillary()
for the key "calcArticleViews". The motivation for this change is to reduce dependencies. If you are getting or putting "calcArticleView" in your extensions you will have to do the same change.