CET Developer Guides
Tutorial: Adopting the new UI style for Extension Libraries
21min
adoption strategy and considerations in general, any ui adoption strategy should account for these steps design and prototyping read through the design system and understanding the design principles is key to unlocking a better user experience and ensuring your user interface is consistent with the rest of the system follow our examples and recommendations, and create prototypes to get a feel of how it would be like before spending countless hours on implementation in configura, we use figma to create prototypes to rapidly iterate and test if the user experience has been improved implementation depending on the breadth of the changes required, using a separate code path (to build a facelift specific library limb tree) for the new features might be required we have also added support in lazy xml to map different toolboxes between ui modes generally, minor changes like updating to the new icon style should not require a new limb tree however, larger changes such as adopting the new features or rearranging the items in the library, will require a new library limb tree to be created testing just like you would with any changes, the new ui should be tested out with users, to validate assumptions and ensure that this is an improvement in user experience and that there are no significant regression bugs metrics like user satisfaction, conversion rate, click rate, task success rate can be used to measure if the new ui is well received review new ui adoption info docid 6gt6if5vsp9epg7g9cpig for recommendations and more details new ui features the new cet ui has introduced new features and a new look for component tab libraries, helping you to achieve a more consistent look and feel while organizing your content or products in a more logical way these features can be enabled by setting the facelift parameter to true when creating the library fika example here's an example of how to migrate an old extension library to the new facelift style, using the fika office extension without utilizing any new images for the sake of simplicity, we will not be using any of the new advanced features, and no icons will be updated to see how to use those new features, refer to extension panel (toolbox) docid 23suuua0qocgzvi80hlva and extension content docid\ k9e w3zzkehm38jtvqkyu step 1 enable facelift mode refactor your code to return a classic and facelift library depending if the user has toggled facelift for extensions using lazy xml, you can specify separate library functions in lazy xml this handles mapping of different function names in components tab configurator \<?xml version="1 0" encoding="iso 8859 1"?> \<lazy extension info> \<main id="custom fika office" /> \<mappings> \<! this section is new > \<mapping classic="custom fika office;buildoldlibrary" 	 facelift="custom fika office;buildfaceliftlibrary" /> \</mappings> \<toolboxes> \<toolbox> \<package>custom fika office\</package> \<function>fikaofficelibrary\</function> \<function>buildoldlibrary\</function> \<! use different function > \<label>fika office\</label> \<sortkey>custom fika#200\</sortkey> \<configid>custom fika all\@predefined\</configid> \<visibility>classiconly\</visibility> \<! add this > \</toolbox> \<toolbox> \<package>custom fika office\</package> \<function>buildfaceliftlibrary\</function> \<! use different function > \<label>fika office\</label> \<sortkey>custom fika#200\</sortkey> \<configid>custom fika all\@predefined\</configid> \<visibility>faceliftonly\</visibility> \<! add this > \</toolbox> \<toolbox> \</lazy extension info> alternatively, if you have no other injection point you can swap out libraries in the library function instead cm / fika office library / public library fikaofficelibrary() { library lib; if (usefacelift) { 	 lib = buildfaceliftlibrary(); } else { 	 lib = buildoldlibrary(); } lib finalize(); return lib; } now we have classic and facelifted libraries for the facelift library function, pass facelift=true into the companylibrary constructor cm / build facelift library / private library buildfaceliftlibrary() { // pass facelift=true into the library's constructor companylibrary lib(root, pkg, facelift=true, // add this companykey="fika", viewmodehook=function foinitviewmodes); return lib; } { // performs shift+click on the current toolbox rebuildcurrenttoolboxcard(force=true); } setting this flag causes the following to happen left/right margins are set to 16px sections use the new style with inline button support buttons will use a white background with a blue border on hover material limbs use the new facelift style with a brush icon after this change, the fika extension library now looks like this step 2 use the new library header the old header at the top is quite large, and scrolls along with the rest of the toolbox contents let's replace this with the new header introduced in facelift which will give us a schemes dropdown for free! cm / build facelift library / private library buildfaceliftlibrary() { // root library limb librarylimb root(pkg, "office", frame=false); / remove this section headerlimb header(root, pkg, "", extendright=true, compact=false, 	 image=foicon("fikaofficeheader png"), margins=(0, 7)); header forcetext = ""; newlinehint(root); headerlimb subheader(root, pkg, "fikaofficeheader", extendright=true, margins=(0, 3)); remove this section / // add additional limbs addfaceliftgloballimb(root); addcatalogselectionlimb(root); addpanelslimb(root); addworksurfacelimb(root); addsupportslimb(root); addtableslimb(root); addlowstoragelimb(root); addupperstoragelimb(root); addchairslimb(root); adddevtoolslimb(root); // specify the library header icon, label, schemekey // schemekey is used to populate the scheme dropdown in the header image headericon = foicon("fikaofficelibrary"); basiclibraryheaderbuilder headerbuilder(headericon, $fikaofficeheader, // pass the propsscheme key here schemekey=cfodataschemekey); companylibrary lib(root, pkg, companykey="fika", 	 facelift=true, 	 headerbuilder=headerbuilder, 	 viewmodehook=function foinitviewmodes); lib finalize(); return lib; } / global stuff / private void addfaceliftgloballimb(librarylimb root) { librarylimb global(root, pkg, "foglobalgroup"); / remove this section appendschemeselector(global, pkg, cfodataschemekey); newlinehint(global); remove this section / } which now gets us the new static library header, with a scheme dropdown on the right step 3 consolidate separate global sections as you can see from the previous image, the global section looks very sparse we can consolidate the two global sections across separate toolboxes cm / global stuff / private void addfaceliftgloballimb(librarylimb root) { librarylimb global(root, pkg, "foglobalgroup"); uiimagehint plhint(showlabel=true, image=foicon("picklist bmp"), 	 textside=right); snapperlimb(global, pkg, "fodatapicklist", plhint); newlinehint(global); uiimagehint uimatlegendhint(showlabel=true, image=foicon("materiallegend bmp"), 	 textside=right); snapperlimb(global, pkg, "fodatamateriallegendsnapper", uimatlegendhint); // new code starts here textsnapperlimb iso(global, pkg, "fikaisoviewrect", image=fikaicon("elevation png"), label=$isoviewscategoryname); newlinehint(global, pkg); uiimagehint checkdrawinghint(showlabel=true, fikaicon("check drawing png"), 	 textside=right, framestyle=coolbuttonframe); voidcallbacklimb(global, pkg, "validatesystemlabel", 	 checkdrawinghint, 	 callback=function checkdrawingcb); uiimagehint uiprojinfo(showlabel=true, fikaicon("project information png"), 	 textside=right, framestyle=coolbuttonframe); voidcallbacklimb(global, pkg, "customerdatadialoglabel", uiprojinfo, 	 callback=function showprojinfocb); // new code ends here } / placeholder for check drawing cb / private void checkdrawingcb() {} / placeholder for show project info cb / private void showprojinfocb() {} this results in the global section to look like this for the picklist, finish legend and elevation tool, we will be refering to product button docid\ l2jrbivjudj7ixbuu tgz to size the buttons correctly check drawing and project information are tools that spawn modal dialogs which will be refering to tool button docid\ slm9kidf g5xog2upu0km we can fix the buttons up with the help of facelift hints a list of facelift hints can be found in cm/core/library/commonhints cm cm / global stuff / private void addfaceliftgloballimb(librarylimb root) { // apply productbuttonmediumtallwithlabel to children limbs librarylimb global(root, pkg, "foglobalgroup", hint=productbuttonmediumwithlabel); //uiimagehint plhint(showlabel=true, image=foicon("picklist bmp"), 	 //textside=right); snapperlimb(global, pkg, "fodatapicklist", 	 image=foicon("picklist bmp")); // specify image //uiimagehint uimatlegendhint(showlabel=true, image=foicon("materiallegend bmp"), 	 //textside=right); snapperlimb(global, pkg, "fodatamateriallegendsnapper", 	 image=foicon("materiallegend bmp")); // specify image // elevation snapper snapperlimb iso(global, pkg, "fikaisoviewrect", // regular snapperlimb image=fikaicon("elevation png"), label=$isoviewscategoryname); //uiimagehint checkdrawinghint(showlabel=true, fikaicon("check drawing png"), //textside=right, framestyle=coolbuttonframe); voidcallbacklimb(global, pkg, "validatesystemlabel", 	 hint=gettoolbuttonhint(6), // override parent hint 	 callback=function checkdrawingcb); //uiimagehint uiprojinfo(showlabel=true, fikaicon("project information png"), 	 //textside=right, framestyle=coolbuttonframe); voidcallbacklimb(global, pkg, "customerdatadialoglabel", 	 hint=gettoolbuttonhint(6), // overide parent hint 	 callback=function showprojinfocb); } this results in the following look for the global section if this was a real port of fika office to facelift, we would take this opportunity to refresh the the icons to account for new look and the sizes i e use 16 x 16 images for the tool buttons step 4 move global to an extension tab to further clean things up, we can separate out the global section to its own tab cm / build facelift library / private library buildfaceliftlibrary() { // root library limb librarylimb root(pkg, "office", frame=false); // create a tab limb for products tablimb productstab(root, pkg, "products"); // append existing limbs into productstab limb instead of root addpanelslimb(productstab); addworksurfacelimb(productstab); addsupportslimb(productstab); addtableslimb(productstab); addlowstoragelimb(productstab); addupperstoragelimb(productstab); addchairslimb(productstab); adddevtoolslimb(productstab); // create a new tab limb for global tablimb globaltab(root, pkg, "global"); // append misc tool limbs into globaltab limb instead of root addfaceliftgloballimb(globaltab); addcatalogselectionlimb(globaltab); // swap basiclibraryheader to to tabbedlibraryheaderbuilder tabbedlibraryheaderbuilder headerbuilder(headericon, $fikaofficeheader, 	 schemekey=cfodataschemekey); companylibrary lib(root, pkg, companykey="fika", facelift=true, headerbuilder=headerbuilder, 	 viewmodehook=function foinitviewmodes); lib finalize(); return lib; } this results in the fika toolbox split into two tabs step 5 re organize panels section let's start by bringing panel symbols and the manager up into product buttons we will also introduce a new tile tools sub section cm / build facelift library / private library buildfaceliftlibrary() { // create a tab limb for products tablimb productstab(root, pkg, "products"); //addpanelslimb(productstab); addfaceliftpanelslimb(productstab); // newly added } / panels / private void addfaceliftpanelslimb(librarylimb root) { // apply productbuttonmediumtallwithlabel to all children limbs librarylimb framegroup(root, pkg, "framegroup", label=$framegroup, hint=productbuttonmediumtallwithlabel); snapperlimb(framegroup, pkg, "fodatapanelframe", 	 //hint=uifixedsizehint(image=foicon("panel frame png"), 	 //preferredsize=prefsize)); 	 image=foicon("panel frame png")); snapperlimb(framegroup, pkg, "fodatawallstart", 	 //hint=uifixedsizehint(image=foicon("wall start png"), 	 //preferredsize=prefsize)); 	 image=foicon("wall start png")); //uiimagehint panelmanhint(showlabel=true, foicon("panel manager png"), textside=right, margins=(8, 4)); voidcallbacklimb(framegroup, pkg, "fodatapanelmanager", 	 //hint=panelmanhint, 	 image=foicon("panel manager png"), 	 callback=function openpanelmanagercb); // introduce a new sub section for tile tools subsectionlimb tiletools(framegroup, pkg, "tiletools", label="tile tools"); // switch the organizer to layout material limbs switchorganizerlimb(tiletools, organizer=faceliftsubsetandbuttongrouporganizer); // swap these material limbs parent from framegroup to tiletools fodatamateriallimb fabricmat(tiletools, pkg, "fabricmaterials", fopanelfabricdom, 	 callback=function fodatatilematanimcb); fodatamateriallimb veneermat(tiletools, pkg, "veneermaterials", 	 fopanelveneerdom, 	 callback=function fodatatilematanimcb); fodatamateriallimb laminatemat(tiletools, pkg, "laminatematerials", 	 fopanellaminatedom, 	 callback=function fodatatilematanimcb); fodatamateriallimb markermat(tiletools, pkg, "markerboardmaterials", 	 fopanelmarkerboarddom, 	 callback=function fodatatilematanimcb); fodatamateriallimb glassmat(tiletools, pkg, "glassmaterials", 	 fopanelglassdom, 	 callback=function fodatatilematanimcb); } as we are using the faceliftsubsetandbuttongrouporganizer, we can remove labelminwidth override from our materiallimb cm / fika office material limb / public class fodatamateriallimb extends dsmateriallimb { / label min width / public int labelminwidth() { 	 //return folibrarymininputw; // let the subsetandbuttongrouporganizer handle this for us 	 return super(); } } this leads up to a nice look for panels, and a sub section for material limbs the next step is to work on the panel / tile animations as the first step, we will be treating them as product buttons cm / panels / private void addfaceliftpanelslimb(librarylimb root) { // smaller header for copy tools headerlimb(framegroup, pkg, "copytoolssubsubheader", forcetext="copy tools", font=faceliftlabelfont, labelcolor=color(77)); newlinehint(framegroup, pkg); animationlimb(framegroup, caopkg, "pickskinanimationg2", 	 //hint=uifixedsizehint(image=foicon("copy config png"), preferredsize=prefsize), 	 label="tile configuration", image=foicon("copy config png"), 	 hint=productbuttonlargewithlabel, 	 applyprops=props{pickfullskin=true}); animationlimb(framegroup, caopkg, "pickskinanimationg2", tooltiptext=$pickskincoloranimationtip, //hint=uifixedsizehint(image=foicon("copy material png"), preferredsize=prefsize), label="tile material", image=foicon("copy material png"), hint=productbuttonlargewithlabel, applyprops=props{picktilemats=true}); newlinehint(framegroup, pkg); // smaller header for place tools headerlimb(framegroup, pkg, "placetoolssubheader", forcetext="place tools", font=faceliftlabelfont, labelcolor=color(77)); newlinehint(framegroup, pkg); animationlimb(framegroup, pkg, "fodatapaneltilesegmentanimation", //hint=uifixedsizehint(image=foicon("tiles 12 png"), preferredsize=prefsize)); image=foicon("tiles 12 png"), hint=productbuttonlargewithlabel); snapperlimb(framegroup, pkg, "fodatapaneltypeelevation", //hint=uifixedsizehint(showlabel=true, image=foicon("panel types png"), 	 //textside=right, preferredsize=prefsize)); image=foicon("panel types png"), hint=productbuttonlargewithlabel); newlinehint(framegroup, spacing=10); } this would be how existing images for animations map out to product buttons as these are animation/tools, to match the facelift guidelines they should be tool button docid\ slm9kidf g5xog2upu0km to use a tool button, you can use the gettoolbuttonhint function and pass along a 16 x 16 image alternatively, you could forego the image with skiprenderimage=true for snapperlimb and animationlimb cm / panels / private void addfaceliftpanelslimb(librarylimb root) { // use tool button hint and set skiprenderimage=true animationlimb(framegroup, caopkg, "pickskinanimationg2", label="tile configuration", //image=foicon("copy config png"), //hint=productbuttonlargewithlabel, hint=gettoolbuttonhint(6), skiprenderimage=true, applyprops=props{pickfullskin=true}); // use tool button hint and set skiprenderimage=true animationlimb(framegroup, caopkg, "pickskinanimationg2", tooltiptext=$pickskincoloranimationtip, label="tile material", //image=foicon("copy material png"), //hint=productbuttonlargewithlabel, hint=gettoolbuttonhint(6), skiprenderimage=true, applyprops=props{picktilemats=true}); newlinehint(framegroup, pkg); // use tool button hint and set skiprenderimage=true animationlimb(framegroup, pkg, "fodatapaneltilesegmentanimation", //image=foicon("tiles 12 png"), hint=gettoolbuttonhint(6), skiprenderimage=true); // use tool button hint and set skiprenderimage=true snapperlimb(framegroup, pkg, "fodatapaneltypeelevation", //image=foicon("panel types png"), hint=gettoolbuttonhint(6), skiprenderimage=true); } step 5 consolidate worksurface and support section for worksurfaces, we start by defining the relevant product button hint into the parent worksurfacegroup limb this hint will apply on all of its children limbs cm / build facelift library / private library buildfaceliftlibrary() { // create a tab limb for products tablimb productstab(root, pkg, "products"); addfaceliftpanelslimb(productstab); //addworksurfacelimb(productstab); //addsupportslimb(productstab); addfaceliftworksurfacelimb(productstab); // newly added addtableslimb(productstab); } / worksurfaces / private void addfaceliftworksurfacelimb(librarylimb root) { // apply the product button hint to the parent library limb librarylimb wsgroup(root, pkg, "worksurfacegroup", label=$worksurfacegroup, hint=productbuttonmediumtallwithlabel); snapperlimb(wsgroup, pkg, "fodatarectworksurface", 	 //hint=uifixedsizehint(image=foicon("worksurface 1 png"), 	 //preferredsize=prefsize)); 	 image=foicon("worksurface 1 png"), 	 label="rectangle"); snapperlimb(wsgroup, pkg, "fodataarcfrontworksurface", 	 //hint=uifixedsizehint(image=foicon("worksurface 2 png"), 	 //preferredsize=prefsize)); 	 image=foicon("worksurface 2 png"), 	 label="arc"); snapperlimb(wsgroup, pkg, "fodata90degcorner", 	 //hint=uifixedsizehint(image=foicon("worksurface 3 png"), 	 //preferredsize=prefsize)); 	 image=foicon("worksurface 3 png"), 	 label="corner"); snapperlimb(wsgroup, pkg, "fodata120degcorner", 	 //hint=uifixedsizehint(image=foicon("worksurface 4 png"), 	 //preferredsize=prefsize)); 	 image=foicon("worksurface 4 png"), 	 label="120 degree"); } the next step would be to consolidate tools for the worksurface into a sub section cm / worksurfaces / private void addfaceliftworksurfacelimb(librarylimb root) { // introduce a new sub section for support subsectionlimb supportsection(wsgroup, pkg, "supportsection", label="support"); boolcallbacklimb toggle(supportsection, pkg, "autosupportsenabled", initial=true, callback=function toggleautosupports); // use the toggle style to get the facelift toggle toggle togglestyle = true; newlinehint(supportsection); // append the support animations voidcallbacklimb(supportsection, pkg, "foaddcantilever", image=foicon("cantileveradd"), callback=function addcantileveranimcb); voidcallbacklimb(supportsection, pkg, "foremovesupport", image=foicon("cantileverremove"), callback=function removesupportanimcb); voidcallbacklimb(supportsection, pkg, "fodefaultsupports", image=foicon("cantileverrestore"), label="apply default", callback=function defaultsupportanimcb); } this gives the worksurface a new steamlined look step 6 combine storage section we can begin by combining the low and upper storage sections, then apply the relevant product button hint to the parent storagegroup (which will propagate to all the child limbs) cm / build facelift library / private library buildfaceliftlibrary() { // create a tab limb for products tablimb productstab(root, pkg, "products"); addfaceliftpanelslimb(productstab); addfaceliftworksurfacelimb(productstab); addfaceliftstoragelimb(productstab); // newly added addtableslimb(productstab); //addlowstoragelimb(productstab); //addupperstoragelimb(productstab); } / storage / private void addfaceliftstoragelimb(librarylimb root) { // apply the product button hint to the parent library limb librarylimb storagegroup(root, pkg, "storagegroup", label="storage", hint=productbuttonmediumwithlabel); snapperlimb(storagegroup, pkg, "fodatalateral", //hint=uifixedsizehint(image=foicon("lower storage 1 png"), //preferredsize=prefsize)); image=foicon("lower storage 1 png")); snapperlimb(storagegroup, pkg, "fodatabookcase", //hint=uifixedsizehint(image=foicon("lower storage 2 png"), //preferredsize=prefsize)); image=foicon("lower storage 2 png")); snapperlimb(storagegroup, pkg, "fodatapedestal", //hint=uifixedsizehint(image=foicon("lower storage 3 png"), //preferredsize=prefsize)); image=foicon("lower storage 3 png"); snapperlimb(storagegroup, pkg, "fodatabookcasetower", //hint=uifixedsizehint(image=foicon("lower storage 4 png"), //preferredsize=prefsize)); image=foicon("lower storage 4 png"), hint=productbuttonmediumtallwithlabel)); newlinehint(storagegroup); snapperlimb(storagegroup, pkg, "fodataoverhead", //hint=uifixedsizehint(image=foicon("upper storage 1 png"), //preferredsize=prefsize)); image=foicon("upper storage 1 png")); snapperlimb(storagegroup, pkg, "fodatashelf", //hint=uifixedsizehint(image=foicon("upper storage 2 png"), //preferredsize=prefsize)); image=foicon("upper storage 2 png")); } step 7 finishing touches following the process outlined in the previous step, we make small refineminets to the table and chair sections cm / build facelift library / private library buildfaceliftlibrary() { // create a tab limb for products tablimb productstab(root, pkg, "products"); addfaceliftpanelslimb(productstab); addfaceliftworksurfacelimb(productstab); addfaceliftstoragelimb(productstab); addfacelifttableslimb(productstab); // newly added addfaceliftchairslimb(root); // newly added //addtableslimb(productstab); //addchairslimb(root); } / tables / private void addfacelifttableslimb(librarylimb root) { // apply the product button hint to the parent library limb librarylimb tablegroup(root, pkg, "tables", label=$tablesgroup, hint=productbuttonmediumwithlabel); snapperlimb(tablegroup, pkg, "fodatarecttable", // hint=uifixedsizehint(image=foicon("table 1 png"), //preferredsize=prefsize)); image=foicon("table 1 png")); snapperlimb(tablegroup, pkg, "fodataroundtable", //hint=uifixedsizehint(image=foicon("table 2 png"), //preferredsize=prefsize)); image=foicon("table 2 png")); } / chair / private void addfaceliftchairslimb(librarylimb root) { // apply the product button hint to the parent library limb librarylimb chairsgroup(root, pkg, "chairsgroup", label=$chairsgroup, hint=productbuttonmediumwithlabel); snapperlimb(chairsgroup, pkg, "fodatachair", //hint=uifixedsizehint(image=foicon("chair png"), preferredsize=prefsize)); image=foicon("chair png")); } which finally results in this to compare the output with "full" facelift that includes new icons, here is a comparison