- Pushing To Sub-Object
- Versioning
- Lazy Schemes
- Embedding Schemes
- UI Layouts
- Presets
- Preset Builder
- Group Code Domain
- Propagate Tool
- PsLayoutConverter Migration Tool
Have you ever wondered....
- How to apply scheme property sub-object of target snapper?
- How to apply to multiple sub-objects of target snapper?
- What if I want to change the key the scheme property is pushed with?
- I want to do something before/after a certain prop is pushed to a certain object.
These problems can all be solved with PropsSchemeProxyPushBehavior
in cm/core/propsScheme.
Pushing To Sub-Object
To push to sub-objects, define a behavior that extends PropsSchemeProxyPushBehavior. You can pass in a translatedReceiver when defining your pushBehavior, based on the original receiver.
- Extend PropsSchemeProxyPushBehavior class
/** * Fika Office Scheme Push Behaviour. */ public class FOSchemePushBehaviour extends PropsSchemeProxyPushBehavior {
- Extend PropsScheme data class and override the pushBehavior method, passing in the receiver item of your choice.
/** * FO Scheme Data. */ public class FOPropsSchemeData extends PropsSchemeData { /** * Push behavior. */ public PropsSchemeProxyPushBehavior pushBehavior(PropObj receiver, str key, Object env=null) { if (receiver as SkinFrame) return FOSchemePushBehaviour(receiver.upSkin.?items.first); }
Pushing to multiple sub-objects
Create one behavior per targetReceiver, and use the PropsSchemeMultiProxyPushBehavior as a holder for all the behaviors.
/** * FO Scheme Data. */ public class FOPropsSchemeData extends PropsSchemeData { /** * Push behavior. */ public PropsSchemeProxyPushBehavior pushBehavior(PropObj receiver, str key, Object env=null) { PropsSchemeMultiProxyPushBehavior multiBehavior(); if (receiver as SkinFrame) { for (tile in receiver.upSkin.?items) { multiBehavior.append(FOSchemePushBehaviour(tile)); } } return multiBehavior; }
Push key control
The only limitation is that the pushProp has to go through the receiving snapper, so if you are trying to push to properties in your sub-object, you need to make sure those properties' defs are exposed onto the main snapper (see appendPropDefs wiki page on how to expose your prop defs). But if you would like to alter the push key, you can override the proxyPushKey method on your extended behavior.
/** * Fika Office Scheme Push Behaviour. */ public class FOSchemePushBehaviour extends PropsSchemeProxyPushBehavior { /** * Proxy push key. * * The push key that facilitates communication between the proxyData * and the pushTarget. * */ extend public str proxyPushKey(str key) { if (translatedReceiver as PanelTile) return spnn("tile", propDefExposureDelimiter, key); return super(..) }
In the case above, we are trying to push to the panel with the key "tile::<propKey>", so you need make sure that this def exists for your panel snapper.
Before/After push
You can override the beforePushProp and afterPushProp method in your extended behavior class if you need to do something there.
/** * Before push single prop. */ extend public void beforePushProp(str key, PropObj source, PropObj receiver, Object value, Object env=null) { } /** * After push single prop. */ extend public void afterPushProp(str key, PropObj source, PropObj receiver, Object value, Object env=null) { }
Nothing is working! Help!
If your push behavior is not working as expected, you can debug the pushProxyObj method to make sure that it is indeed trying to push with the key and value you expect. If those are correct, you might have to dig deeper into the pushProp method. Fear not, if you need some special parameter for your push props to work (for example an pusher env or receiver env to control the pushPropBail), all that can be overriden in your push behavior.
/** * Push proxy data. */ extend public bool pushProxyObj(str key, PropObj source, PropObj receiver, Object value, Object env=null) {
Versioning
Added versioning capabilities to deal with systemKey change and other data changes between different versions of schemes.Version number can be increased in code, through the version() function in the PropsScheme class.This version is saved and can be checked upon loading.
/** * Semantic version. * Used for version check during loading scheme. */ extend public Semver version() { return Semver(); }
There are 3 places where this can be checked:
- SystemKeyRenameHooks (propsSchemeManager.cm)
- PropsSchemeLoadVisitor class – loadedVersion field (propsSchemeVisitors.cm)
- afterLoad function (propsScheme.cm)
You can rename your systemKey as below:
/** * Init. */ init { registerPropsSchemeSystemKeyRenameHook(function renameKitchenDemoSystemKey); } /** * Rename method. */ public void renameKitchenDemoSystemKey(Str name, Semver ver) { if (name.?v == "Kitchen_Cabinet_Scheme") { name.v = cKDCabinetSchemeKey; } }
Load visitor:
/** * Load scheme visitor. */ public class PropsSchemeLoadVisitor extends PropDefVisitor { /** * Loaded version. */ public Semver loadedVersion;
After load in propsScheme.cm:
/** * After scheme is loaded. */ extend public void afterLoad(Semver loadedVersion) { lazyLoadedData = null; }
Lazy Schemes
Introduced concept of lazy schemes, where the scheme's data and domain are never initialized until its needed.
Solution for PropsScheme – quickLoad
Schemes are loaded with the quickLoad option, where the scheme's values are stored in the scheme object temporarily. When the scheme data is asked, that’s when we assign the loaded values to the scheme data
Class: PropsScheme
/** * Init data. */ extend public void initData(str->Object args=null) { bool initData; if (!_data) { initData = true; data = constructData(); } data.key = "schemeData"; data << #propsData; data.defs = null; data.propDefs(); data.putArgs(args); if (initData) { if (default) { addDefaultValues(); appendDefaultPreference(); excludeAllSchemePropDefs(); } else { if (lazyLoadedData) { propsSchemeManager.finalizeLoadedScheme(this, lazyLoadedData, highlight=drawing); } else if (is("addDefaultValues")) { addDefaultValues(); excludeAllSchemePropDefs(); } } } } /** * Prefer quick load? */ extend public bool preferQuickLoad() { return true; }
Solution for Catalog Schemes – LazySchemes
Lazy schemes are added to the container, when they are accessed, we create the real scheme that replaces the lazy scheme
/** * Activate props scheme layout. * Before building the selected scheme, scheme design needs to be synced with catalog first. */ public PropsScheme dsActivatePropsSchemeLayout(PropsScheme scheme) { if (scheme as DsPsLayoutLazyPropsScheme) { PsLayout schemeLayout = scheme.schemeLayout; DsPData data = scheme.pData; if (schemeLayout and data and data.prdCatalog) { dsSyncPsLayoutData(schemeLayout, data); schemeLayout.initLabel(dsLanguageIDs); schemeLayout.quickLoad = false; scheme.restoreCurrentSchemeSelection(); if (PsLayoutPropsScheme loadedScheme = buildPsLayoutPropsScheme(schemeLayout)) { loadedScheme.put("dsCatCid", data.dCatCid); loadedScheme.put("dsCatEnterprise", data.enterprise); loadedScheme.data; // init data here removePropsScheme(scheme.systemKey); propsSchemeManager.removeSchemes(scheme.systemKey); addDefaultPropsScheme(loadedScheme); return loadedScheme; } } } return scheme; }
Embedding Schemes
- Embedded schemes are saved as memoryStream in the world auxillary.
- They are loaded into the Scheme Container like normal schemes, and saved to the world auxillary when the drawing is saved.
- This is enabled for all schemes and you don't have to do anything to enable this functionality.
- If you already have a scheme with the same name in your current container, the drawing scheme will be loaded as a copy with a suffix, ie: "Drawing scheme (1)".
- There is now a filter that allows you to filter out your schemes, drawing schemes, default schemes and preset groupings.
- We also added Auto-embed function. When turned on, will automatically embed all used schemes (every scheme that was applied to the drawing, or have snappers initialized from it) to the drawing. When the drawing is shared, all embedded schemes will be accessible.
Comparison between embedding and saving:
Embed | Save |
Gets saved with the drawing | Saved on the user's machine locally |
When another user opens the drawing, the can see and use all schemes embedded to that drawing | Saved schemes are only accessible on the local machine |
Will increase drawing size | Does not affect drawing size |
Auto embed will embed all used schemes only (applied from dialog or used during initFromPropsScheme) | Auto save will save all edited schemes |
Grouped under "Drawing" filter group | Grouped under "My Schemes" filter group |
UI Layouts
We added vertical layout to aid users that uses a lot of schemes at one time.
Presets
- Presets are schemes with predefined property values. Presets can be defined by the extension owner.
- For example, kitchen extensions has several presets of different styles, ie: Modern Wood, Artic white etc
- This allow users to quickly change between different suggested schemes.
- It can also be used to recommend new material options, manufacturer preferred combinations.
- A preset can be published via catalog creator or through code in extension.
To do it in code, override the scheme class to provide urls of cmScheme files and their image paths (they need to be shipped as part of your extension). You can also define how they should be grouped.
/** * Preset urls. */ public Url[] presetUrls() { Url[] urls(); Url path = cmFindUrl(cKDPresetsPath); for (e, url in Directory(path # "*.cmScheme")) { urls << url; } return urls; } /** * Preset image path. */ public Url presetImagePath(bool isThumbnail, sizeI targetSize=(-1, -1)) { if (!preset) return null; Url path = cmFindUrl(cKDPresetsPath); path.setFileName(label); for (format in ["cmjpg", "png", "jpg"]) { path.changeSuffix(format); if (path.isReadable) { return path; } } return null; } /** * Preset group key. */ public str presetGroupKey() { if (preset) { if (label.beginsWith("Classic")) { return "Classic"; } if (label.beginsWith("Modern")) { return "Modern"; } } return super(); }
Preset Builder
- To build your your preset in the catalog creator scheme card, you first need to toggle on the show/hide preset.
- A preset column will show up, where user can create groups for the presets, name each preset and upload preset previews.
- The preset preview can be rendered directly from the scheme card or imported from PhotoLab.
- Presets created need to be uploaded.
Group Code Domain
There are situations where one might want to create an entry that contains a merged domain of all features with a specific group code.
- To do this, just drag an entry from the Group Code section and a group code entry will be made with a concatenated domain.
- This is especially helpful if your feature code changes frequently, as long as the group code remains the same
Propagate Tool
- Added functionality to allow propagate in catalog creator scheme card
- Propagate is the fast forward button that pushes the value of this property to other properties in the same scheme
PsLayoutConverter Migration Tool
The PsLayoutConverter is a basic object for taking an existing scheme and making a PsLayout object for it.
Currently it supports creating a PsLayout from a CoreScheme.
The intent behind this object is to either use it directly, or to override the buildEntryFromCoreScheme() method to create PsLayout objects to help transfer over to the new PsLayoutPropsScheme class.
The generated PsLayout object can be saved out to a file, or used for reference when programmatically making a scheme.
Example:
PsLayoutConverter converter(); MyScheme scheme("test"); PsLayout temp = converter.convertCoreScheme(scheme); temp.dump(); // this is to make sure the layout was fully converted correctly.
Comments
0 comments
Please sign in to leave a comment.