cm.abstract.dataSymInterface

Updated:

The valueS() function in DsiPDataOption was updated to now return specialCode if there is one.

// dsiPDataOption.cm
Old: 
extend public str valueS() {
	if (_dataType.Character) return code;
	...
}

New: 
extend public str valueS() {
	if (_dataType.Character) return specialCode ?? code;
	...
}

cm.abstract.dataSymbol

Updated Interfaces:

The generateSifOptionRows function in DsPData was updated to take a DsPart as a parameter.

// dsPData.cm
Old: final public void generateSifOptionRows(SifEnv env, Option o, DsiPDataOption pO, int level=0) : deprecated
New: final public void generateSifOptionRows(SifEnv env, Option o, DsiPDataOption pO, DsPart part=null, int level=0)

Updated:

The generateSifOptionRows function in DsPData was updated to export a CustomerOwnMaterial code and description for a DsiPDataOption where appropriate.

Added:

The dsGenerateCOMPartsHook was added as part of the rawPartListHooks. It gathers CustomerOwnMaterials on DsPDatas and generates child COMParts from these materials.

// hooks.cm

/**
 * Append COMParts from Part.
 * (COMParts hook)
 */
package Part[] dsGenerateCOMPartsHook(Part[] parts, Space space) {
    for (part in parts) {
	Snapper snapper = part.owner;
	generateCOMParts(snapper, part);
    }

    return parts;
}

cm.abstract.material

Deprecated functions:

  • public void build() : deprecated
    • public void rebuild() updates the dialog
  • public void editTFCB() : deprecated
    • use public void controlCb(Control c)
  • public void updateTF() : deprecated
    • use public void update()

cm.abstract.materialHandling

MhFrameUpdateBayHeightFunction changes

As mentioned under Compile Time Changes, MhFrameUpdateBayHeightFunction has been renamed to MhFrameHeightChangeUpdateBayFunction. This was changed to more accurately reflect the logic of the class. Additionally, the function key associated with this function has already been changed:

Old: res << MhFrameUpdateBayHeightFunction("frameUpdateBayHeight");
New: res << MhFrameHeightChangeUpdateBayFunction("frameHeightChangeUpdateBay");

All calls of "frameUpdateBayHeight" have been updated to "frameHeightChangeUpdateBay" in the abstract, you will need to do the same as well in your extension.

MhBayEditorMeasurementsBehavior changes

The measurements() method has had some of its code moved out into seperate methods getBayHeightMeasurements() and getLevelHeightMeasurements().

    /**
     * Get bay height measurements.
     */
    extend public void getBayHeightMeasurements(<line, double, point>[] lines,
                                                MhSnapper owner, box b,
                                                double offset) {
        double lbh = owner.shapeBoundWithChildren(symbols=[sLevel, sUnitLoad]).h;
        double frameH = lbh;
        forChildren(snapper in owner.rootParent) if (snapper as MhSnapper) {
        
        // Frame Height
        lines << <line(b.p0, (b.p0.point2D, frameH)), offset, (0, 1, 0)>;
    }


    /**
     * Get level height measurements.
     */
    extend public void getLevelHeightMeasurements(<line, double, point>[] lines,
                                                  MhSnapper owner, box b,
                                                  double offset) {
        double last = 0;
        double lastZ = 0;
        for (MhSnapper l in owner.getSortedChildren(), index=i) {
            if (l.isLevel) {
                // Level height (between levels).
                double curr = l.toSpaceTransform.pos.z;
                lines << <line((b.p1.x, b.p0.y, last), (b.p1.x, b.p0.y, curr)), offset, (0, -1, 0)>;
                last = curr;

                // Level height - frame height.
                box lb = l.shapeBound([sLevel, sLevelFrame]);
                double z = curr - lb.h;
                lines << <line((b.p1.x, b.p1.y, lastZ), (b.p1.x, b.p1.y, z)), offset, point0>;
                lastZ = l.localBoundWithChildren.p1.z + curr;
            }
        }
    }

MhSpecificConfigurationBehavior changes

Removed specific configuration behaviors as default behaviors for the bay, frame, and level spawners.

Affected spawners:

  • MhBaySpawner
  • MhFrameSpawner
  • MhLevelSpawner
  • MhRackFrameSpawner
  • MhRackLevelSpawner

MhStorageConfiguration changes

The field preview has been moved down from MhRackingConfiguration in the cm.abstract.materialHandling.storage.racking package into MhStorageConfiguration in the cm.abstract.materialHandling.storage package.

public class MhStorageConfiguration extends MhSystemConfiguration {

    /**
     * Preview
     */
    public MhStorageConfigurationPreview preview : copy=null, stream=null;
}

You do not need to add any load code as this field is not streamed.

This class also now generates and returns a preview by default. If you do not wish to see a preview in your pre configurator, you will have to override the configurationPreview() method.

Old:
    extend public MhStorageConfigurationPreview configurationPreview() { return null; }


New:
    extend public MhStorageConfigurationPreview configurationPreview() {
        if (!preview) preview = MhStorageConfigurationPreview();
        return preview;
    }

MhEngineManager changes

New method updateSystemsAfterExport added to engine manager that runs after export instead of after the initial export. alignAllSnapped of the rows is now done in updateSystemsAfterExport instead of updateSystemsAfterInitialExport.

New: extend public void updateSystemsAfterExport(MhSystemEngineEnvironment env, MhSystemCollection[] systems,
                                                 Snapper{} snappers, MhEngine engine)

More control over which engine runs are executed using space

Currently when calling mhRunEngines(), all collected engine runs will be ran. We have introduced the ability to only run specific engine runs by passing in a space to MhRunEngineEnv. If space has been passed into the engine run env, when running engines, we will not execute any engine runs that do not match the engine related to the given space.

public class MhEngineManager extends CoreObject {

    /**
     * Run all engines.
     */
    extend public void runEngines(MhRunEngineEnv runEnv=null) {
        ...
        Space space = runEnv.space;
        for (e, list in engineRunList) {
            ...
            if (space and e != mhEngine(space, createIfNone=false)) continue;
            ...
        }
        ...
    }
}

Here are the changes we made to now use space when running engines:

  • Pre configurator previews now only run engine runs related to the preview space when populating preview snappers.
public class MhStorageConfigurationPreview extends PropObj {

    /**
     * Populate the preview snappers.
     */
    extend public void populatePreviewSnappers(MhStorageConfiguration config,
                                               MhStorageConfigurationItem item=null) {
        ...
        mhRunEngines(MhRunEngineEnv(space=previewSpace, blockFinalize=false, blockExport=true));
        ...
    }


    /**
     * Spawn preview snappers.
     */
    extend public void spawnPreviewSnappers(MhStorageConfiguration config) {
        ...
        mhRunEngines(MhRunEngineEnv(space=previewSpace, blockExport=false));
    }
  • MhSnapper validate event for sRunEngines will now only run engine runs for the snapper's space.
public class MhSnapper extends Snapper {
    /**
     * Validate 'k' (change to set).
     */
    public void validate(symbol k, Object env=null) {
        ...
        switch (k) {
          case sRunEngines: {
              ...
              mhRunEngines(MhRunEngineEnv(space=space, blockFinalize=true, initiator=initiator));
              ...
          }
        ...
    }
  • The mhRunEngines() call at every #endUndoStep event viewed by MhEngineManagerEventViewer has been changed to first collect all spaces related to the undo step and then call mhRunEngines() for each collected space.
public class MhEngineManagerEventViewer extends EventViewer {

Old:
    /**
     * Event being fired.
     */
    public bool event(symbol event, Object z, str->Object args) {
        if (event == #endUndoStep) {
            if (?UndoStep step = z) {
                ...
                mhRunEngines(MhRunEngineEnv(blockFinalize=false, blockExport=true));
            }
        }
        ...
    }


New:
    /**
     * Event being fired.
     */
    public bool event(symbol event, Object z, str->Object args) {
        if (event == #endUndoStep) {
            if (?UndoStep step = z) {
                Space{} spaces(4);
                for (MhSnapper s in step.referred) {
                    if (!s.isAlive) continue;
                    spaces << s.space;
                    ...
                    }
                }

                for (s in spaces) mhRunEngines(MhRunEngineEnv(space=s, blockFinalize=false, blockExport=true));
            }
        }
        ...
    }
}

cm.abstract.materialHandling.storage.racking

Tunnel graphics

Tunnel graphics will no longer be shown during rendering. The line that removed the tunnel from the rendering is as below:

public class MhTunnelGfxBehavior extends MhGenericGfxBehavior {

    /**
     * Tunnel 3D.
     */
    extend public Primitive3D tunnel3D(MhSnapper owner, FetchEnv3D env) {
        ...
        p.layer = not(#render);
        ...
    }

This change is made in tunnel3D() from the MhTunnelGfxBehavior class, located in behavior/mhTunnelGfxBehavior.cm. So any tunnel that uses this class and method will no longer be rendered, and this method will have to be overriden if you would still like the tunnel to be shown.

cm.abstract.materialHandling.storage.shelving

MhShelvingBayConfigurationItem changes

The method updateBayHeight() has been updated to use logic similar to other storage extensions. It relies on the mhCalculatedBayHeightForConstruction() function.

No floor level by default

We do not expect shelving products to have floor levels and so have update MhShelvingBayEngineBehavior to not generate floor levels by default.

public class MhShelvingBayEngineBehavior extends MhBayEngineBehavior {

    /**
     * Add floor level.
     */
    public bool addFloorLevel(MhSnapper snapper) { return false; }


    /**
     * * Accepts function run.
     */
    public bool acceptFunctionRun(MhSnapper snapper, MhEngineFunctionRun func, symbol event="", Object env=null) {
        str funcName = func.name;
        if (funcName == "bayEnsureFloor") return false;
        return super(..);
    }
}

See "New pre configurator classes" about the new `MhShelvingConfiguration class which mentioned overridden logic to support no floor levels.

Default shelving clearance spec

MhShelvingClearanceConfigurationItem now returns a MhShelvingClearanceSpec object by default for defaultClearance().

public class MhShelvingClearanceConfigurationItem extends MhClearanceCompartmentConfigurationItem {

    /**
     * Default clearance.
     */
    public MhClearanceSpec defaultClearance() {
        return MhShelvingClearanceSpec();
    }
}

cm.abstract.storage.racking.selective

Selective Racking extension changes

Selective racking extension now extends from generic Extension class.

Old: private class AbstractSelectiveRackingExtension extends AbsRackingExtension
New: private class AbstractSelectiveRackingExtension extends Extension

cm.basic

Changes / Fixes to weak collections

Previously, if a sequence was declared as 'weak', it would also clear out null values when the sequence is resized. This would cause the observed contents of the seqeunce to change at what would appear to be an arbitrary time. With this release, these sequences will no longer clean up null values on resize.

When streaming a collection with weak values, the object loses the weak value attribute when being streamed back in. This functionally meant that all unstreamed collections would not have the weak value attribute, regardless of their state before streaming. As of this release, the weak value attribute will be respected when un-streaming.

cm.core

cm.core

Added:

A function to collect any additional child parts has been added to the OrderExporter. This is to catch COMParts that are appended during rawPartsListHooks.

// orderExporter.cm
extend public void collectAdditionalChildParts(Part[] parts)

cm.core.dwg

class DwgBspEntry

DwgBspEntry is now responsible for caching graph.bound.

To utilize the cache, access the bound by calling DwgBspEntry::bound() rather than DwgBspEntry::graph.bound(). The latter will always return a freshly calculated bound, while the former is cached.

Also, be mindful that you do not mutate a Graph owned by a DwgBspEntry in a way that affects it bound after its initialization, as this does not automatically clear the cache.

cm.core.graph

Fixed a bug in gText.cm where evaluatedSize() did not properly respect the scale argument. It only updated the font with the scale, bus assumed the scale for the actual size was 0.001.

You can ignore this if you do not manually call evaluatedSize. If not, note that evaluatedSize is now scaled up by a factor of scale / 0.001 compared to previous versions of CET.

cm.core.library

The following changes were made to support development efforts of the new UI.

A new automatic caching system has been added for extension libraries, so any custom caching should be removed in order to not conflict with it.

UIHints now apply to children of the LibraryLimb as well. This allows applying the same hint to all child limbs without explicitly passing it in to each one. You can still override the hint by applying a different hint to the limb.

cm.core.part

File Part.cm

semiHidden() is no longer a condition in isVisibleInMaterialList() as a way of including child parts during exports.

// part.cm

Old: 
public bool isVisibleInMaterialList(Part part, bool expand, bool child) {
    bool view;

    if (!part.visibleInMaterialList())
      view = false;
    else if (part.zeroQuantity(true))
      view = false;
    else if (part.canceled())
      view = false;
    else if (part.semiHidden())
      view = false;
    else
      view = true;
    
    return view;
}

New:
public bool isVisibleInMaterialList(Part part, bool expand, bool child) {
    bool view;
    
    if (!part.visibleInMaterialList()) {
	view = false;
    } else if (part.zeroQuantity(true)) {
	view = false;
    } else if (part.canceled()) {
	view = false;
    } else {
	view = true;
    }
    
    return view;
}

class PartInfoTree

A method for building the columns for a PartInfoTree was added. When a PartInfoTree is being built in the CalculationGridWindow, this method is called to build it's columns.

Added: extend public void buildColumns(CalculationGridWindow grid, int row, Space space) {

cm.core.toolbox

The toolbox card width has been updated when running CET in new UI. This matches our new design system for component tab libraries.

  • classic UI: 296 px
    • usable width for existing libraries: 290 px
  • new UI: 312 px
    • usable width for existing libraries: 290 px
    • usable width for adopted libraries: 280 px

For existing libraries that are not adopting to newUI (i.e. useFacelift=false):

  • CET will run your exsting library in a compatibility mode
  • This would mimic the classic UI library width of 290 px.
  • Existing toolbox layout is maintained across classic UI and new UI

For the best experience in new UI, consider adopting your component library for the new UI. https://dev-docs.configura.com/design-system/tutorial-adopting-the-new-ui-style-for-extension-libraries

For more information on what is possible with libraries in new UI: https://dev-docs.configura.com/design-system/component-tab-libraries

cm.core.user

Developers could previously add hooks for updating toolbox style treeviews when a style is updated by appending to updateToolBoxHook.

In addition to this, they would need to append a SelectWorldHooks to rebuild the treeview when the world changes (as different worlds have different saved styles).

Developers should no longer add a SelectWorldHooks to update toolbox drop downs, if they are already updated in hooks in updateToolBoxHook. All updateToolBoxHook are now called automatically when a new world is selected.

Updating via SelectWorldHooks should not cause functional issues, but may impact performance, as the update will happen twice.

cm.format.dwg

cm.core.dwg.dwgExporter.cm

Added new field to cache already exported materials.

Added: private str->DwgMaterialData cachedMaterials();

cm.win

The following changes were made to support development efforts of new UI.

Origin fixes

The origin of parent Windows will now be respected when doing operations like extendRight, extendBottom, extendBottomRight, and any other positioning functions, which may affect the layout of your dialogs.

Font changes

The new UI comes with a different larger font, which may affect the layout of your windows. This typically shows up in the various forms:

  • clipped font descent texts (i.e. letters g, j, p, q, y getting clipped)
  • Input text fields getting cropped off

Some common classes that are affected:

  • GridCell used in GridWindow
  • SectionedLabel

Improvements for Card

Hidden cards no longer get size updates from their parent parent CardWindow. This is to improve resizing performance. Instead, CardWindow will call parentClientBoundChanged before your card is shown.

To handle custom layout logic, you may can override Card's parentClientBoundChanged:

    /**
     * Parent client bound changed.
     */
    public void parentClientBoundChanged() {
        sizeI prevSize = size();
        super();
        if (size() != prevSize) updateLayout();
    }

Card are no longer constructed with a hardcoded size of (100, 100) to improve performance.

MenuBar size and margins

Upon constructing a MenuBar, you need to perform a finalize() method call.

    CoolMenuBar menu(parent);
    buildFileMenu(menu);
    buildEditMenu(menu);
    buildManufacturersMenu(menu);
    menuBar.finalize();

The finalize method call performs the following:

Call finalizeSubMenu to ensure sub menu margins consistent.

Perform an autoSize to calculates appropriate width and height.

Resize and reposition xControls as required during parentClientBoundChanged

Changes to repaintFrame

The following classes no longer paint frames in repaintFrame.

  • ShrinkBox
  • ShrinkWindow
  • SubGroupBox

Subclasses of the above classes should migrate their repaintFrame overrides to repaint. In most cases a rename of the method signature would suffice.

Removed: public bool repaintFrame(mdc hdc, rectI r)
Replace: public bool repaint(mdc hdc, rectI r)

If you have code that used to call repaintFrame(), you should replace it with refreshFrame()

Old: repaintFrame();
New: refreshFrame();

In future releases, we will try to remove repaintFrame in more places.