Getting Your WayBuilding Custom UI Elements It may be, however, that you are interested in going further and building your own tools with interfaces. This section will go through the process of creating a simple tool and making it work both as a floater and as a dockable toolbar. To do this, we'll explore writing proof-of-concept code, prototyping the UI in the Visual MAXScript editor, and then putting code and interface together to make a fully-working tool.quickDraft: A Render Settings Manager 3ds max's render presets, introduced with max 6, are good for managing multiple output formats or render element passes on larger projects, but I find that they slow down the workflow I actually use most of the time: turning off a few settings to speed up test renders. With the tabbed Render Scene dialog, introduced in the same release, I also find it easier to miss turning a needed setting back on before committing to a long render, which adds to my stress level.So, do I grumble to myself and hope the designers change their minds for max 8? No! With MAXScript, it's easy to write custom UI tools. The script we'll be writing in this section is called quickDraft, and the aim is to address these problems and force fewer trips to the Render Scene dialog.Designing the Script The first step is to write out some design goals. This is analogous to storyboarding an animationit keeps you focused on the goal while you're immersed in the details. My design goals are as follows:- To control the on/off state of various speedups for the scanline renderer.
- To have a quick, one-stop way to preflight production render settings.
- To take up very little room in the interfacescreen space is always precious.
It's clear from looking at this list that the first two goals need a little elaboration. We want to know specifically what settings this tool is going to let us adjust, so let's create another list:- Render Hidden Geometry
- Rendered Frame Window
- Save File toggle
- Elements Active
- Antialiasing
- Disable All Samplers
- Shadows
- Area Lights/Shadows as Points
- Enable Raytracing
- Atmospherics
- Render Effects
- Displacement
- Video Color Check
- Auto-Reflect/Refract and Mirrors
The list was a little long, so I got rid of some of the features that I initially thought I wanted but really don't use much. After all, this is my custom tool, and I want absolutely no clutter. Your custom tool might need different controls (for example, you might find a motion blur toggle essential, or want to build your tool to work with mental ray or a third-party rendering plug-in). Remember, it's all about workflow.Proof-of-Concept Code Before investing the time in writing a script, it's a good idea to make sure the overall functionality is workable in MAXScript and to sketch out the script's core functions. The best place to start with this is the MAXScript Reference file.
1. | Open the Listener and the MAXScript Reference (Help > MAXScript Reference). | 2. | Since we'll be controlling the renderer, go to the Search tab of the Reference file, input renderer, and then click List Topics. Double-click Renderers, the first topic in the list.Note | By default, all instances of the word you searched for will be highlighted in the Reference page. While this is useful when looking for a specific command within a long list, it can be distracting when the word appears many times on a page. Use Options > Search Highlight Off and reload the page if you want to get rid of the highlighting. |
| 3. | The first property listed on the Reference page is renderers.current. Enter it in the Listener, and note that MAXScript returns Default_Scanline_Renderer:Default_Scanline_Renderer (as long as that is the current renderer!). | 4. | Scroll down to the bottom of the Reference page and click the link to Default_Scanline_Renderer : RenderClass.You are now on a page that shows the properties of the Default Scanline Renderer that can be set through MAXScript. Some of these properties are ones we want to be able to set with quickDraft, like .shadows, the second entry. | 5. | Open the Render Scene dialog, click the Renderer tab, scroll it so that you can see the Shadows check box, then input the following in the Listener and press Enter: renderers.current.shadows = false
The Shadows check box in the Render Scene dialog cleared when you pressed Enter (and will become checked again if you input code to set the property to true). In other words, you have now verified that this is the code you want to have executed when your tool's Shadows check box is unchecked. | 6. | Look up the parameter names for the other functions described in your design document. A few are listed on this page of the Reference (.antiAliasing, .enablePixelSampler), but you will need to search other topics to find them all"Render Scene Dialog" in particular. Some of the parameters will need to be changed using a different approach because they are not subproperties of renderers.current. Space does not permit a full explanation here, but refer to the comments and working code in quickDraft_proof_of_concept.ms on the DVD to learn more. |
Sketching the Interface Now that we know what we want to do and know that it's possible, it's time to lay out the interface. While it is possible to code a UI by hand, and many experienced scripters prefer to do so, a utility called Visual MAXScript (VMXS) enables us to create an interface using drag-and-drop methods (Figure 6.4).
1. | From the MAXScript menu choose New Script. | 2. | In the MAXScript Editor window choose Edit > New Rollout. Notice that the script window becomes grayed out and inaccessible; until Visual MAXScript is closed, the rest of the script will be locked.Note | There are two ways to access Visual MAXScript, and the way you choose affects the behavior of the editor: MAXScript menu > Visual MAXScript Editor in the main interface, or Edit > New Rollout or Edit > Edit Rollout from within a MAXScript Editor window.If you open Visual MAXScript from the main interface, you will need to save the UI code you create to an .ms file, and then open the file and copy and paste the code into your script in order to use it.Opening Visual MAXScript from an editor window will connect VMXS to the script you are writing. When you choose File > Save, UI code will be written directly into your script. This is usually an easier way to work. |
| 3. | The right side of the editor is the Properties Page, which displays the properties of the rollout you're editing. Change the name property to quickDraft_rollout, and caption to quickDraft. The name is how you'll refer to the rollout in your code, while caption is the title of your tool window in the interface. | 4. | Continuing down the Properties Page, set width to 111 and height to 216. This makes our rollout more compactjust big enough to hold a column of check boxes and their captions. | 5. | Click the icon for the check box widget at the bottom of the VMXS window, and then drag a box in the gray area on the left. A check box named Checkbox will appear, and the Properties Page on the right will show the check box's properties instead of the rollout's (Figure 6.5).Figure 6.5. Click the widget's icon, and then drag in the Layout window to create a check box. [View full size image] | 6. | Change the name property to hidden, and the caption property to Render Hidden.Tip | A UI element's name property cannot contain spaces, nor can it have a digit as the first character. |
| 7. | If the caption looks cut off, drag the check box's sizing handle to make it wide enough for the entire caption. | 8. | Set the check box's height property to 14 using the Properties Page. This is the "normal" height of most UI elements. | 9. | Choose File > Save in the VMXS window. Rollout code is written to the MAXScript Editor window, although it remains grayed out.Tip | The Visual MAXScript Editor has no undo. Be sure to save your UI code frequently, so that you can close and reopen the editor to revert to an earlier version of your layout if you make a mistake. |
| 10. | Create a new check box widget by clicking the Selection tool icon, selecting the Render Hidden check box, and pressing Ctrl-C to copy followed by Ctrl-V to paste. Drag the new check box to approximately the right position, and change its name and caption properties to rfw and RFW, respectively. Don't worry about getting the position exactly right; Visual MAXScript has alignment tools to help clean up the layout. | 11. | Repeat the paste-move-rename operation nine more times, to create a total of 11 check boxes. Use the following names and captions (Table 6.3):Table 6.3. quickDraft Check Box Properties Name | Caption |
---|
hidden | Render Hidden | rfw | RFW | save | Save File | elements | Elements Active | aa | Antialiasing | samp | Disable Samp. | shad | Shadows | area | Area as Point | raytrace | Raytracing | atmo | Atmospherics | displace | Displacement | Now that all your check boxes are built and named, it's time to align them. | 12. | Choose File > Save to write out code to the MAXScript Editor. This will give you a revert point if you don't like the results of the next step. | 13. | With the Selection tool active, drag-select all the check boxes and choose Layout > Align > Left, then Layout > Space Evenly > Down. If you don't like the layout, you can revert, move your check boxes around manually, and repeat the alignment commands.If you want to revert, close the Visual MAXScript Editor without saving, then choose Edit > Edit Rollout in the MAXScript Editor. Keep adjusting the UI elements until you like the layout. In my version, I decided to indent Area as Point as a subproperty of Shadows, since it's meaningless if shadows are turned off altogether (Figure 6.6).Figure 6.6. The Align and Space Evenly commands help you make a clean-looking interface. [View full size image] Note | You can nudge elements by using the arrow keys, and constrain mouse drags to a straight line by holding down Shift. |
| 14. | When you're satisfied with the layout, choose File > Save in the Visual MAXScript Editor, close Visual MAXScript, and save your script as quickDraft_interface01.ms. Reopen Visual MAXScript by pressing F2. The layout shown in Figure 6.6 is saved on the DVD as quickDraft_interface01.ms.Conceptually, there are two types of controls in quickDraft: controls related to file saving, whose proper settings will vary with the project; and render speed-ups that will almost always be set the same way for production renders. In the layout shown in Figure 6.6 I've put some space between the two groups, but it would be nice if there were a more definite visual cue for the difference. | 15. | Click the Group Box widget icon (it's immediately to the left of the Check Box widget icon you used before), and drag a frame around each of the two groups of check boxes. | 16. | Use the Group Boxes' size handles to adjust the border to your liking, and change their caption properties to Render Controls and Speed-Ups (Figure 6.7). This layout is saved on the DVD as quickDraft_interface02.ms.Figure 6.7. The completed quickDraft UI. [View full size image] | 17. | Use Visual MAXScript's Save command to write your finished interface code into the MAXScript Editor, close VMXS, and save your script as quickDraft_interface02.ms. |
Figure 6.4. The Visual MAXScript Editor is a drag-and-drop tool for designing scripted interfaces. [View full size image] Congratulations! You've built a complete and polished UI using Visual MAXScript. Now it's time to hook up the proof-of-concept code to the interface code, and to make it launchable as a tool from within 3ds max.Building a Fully Operational Utility
1. | Relaunch Visual MAXScript from the MAXScript Editor window (open quickdraft_interface02.ms first if you are not continuing from the previous exercise). | 2. | In the main menu, choose MAXScript > Open Script... and open quickDraft_proof_of_concept.ms from the DVD. | 3. | Select the Render Hidden check box in the Visual MAXScript Editor, and click the Event Handlers tab at the top of the Properties Page.Event handlers are blocks of code whose execution is triggered by certain events. One such event is when a check box is turned on or off. When the user clicks a MAXScript check box, the code in the check box's changed handler is triggered, or called, and the current on/off state of the check box is given to the event handler code as a variable named state. | 4. | Click the changed event handler. An Edit Event Handler window opens in which we can enter the code we want to associate with the Render Hidden check box's state change. | 5. | Find the Render Hidden entry in the proof-of-concept code, copy and paste it to the Edit Event Handler window (Figure 6.8), and click OK. Repeat for each of the other UI elements.Figure 6.8. Copying proof-of-concept code into event handlers in Visual MAXScript. [View full size image] Note | There are two entries for the Render Elements check box in the proof-of-concept file. The code for the event handler is the first entry; the second is an example and is not used in the script. |
| 6. | Choose File > Save to write the code out to the MAXScript Editor, close Visual MAXScript, and save your script as quickDraft_interface03.ms.We're almost ready to test our utility. We just need to add a line of code to the end of the script that launches our rollout as a dialog, a floater containing our UI elements. | 7. | To the very end of the script, after the last closing parenthesis, add a new line: createDialog quickDraft_rollout width:111 height:216 escapeEnable:false
| 8. | Choose File > Evaluate All in the MAXScript Editor. Your UI code appears as a fully functional floater in the interface. Open the Render Scene dialog and test each of the check boxes in quickDraft, watching the state of the equivalent controls in the Render Scene dialog to make sure that they work.If you don't have any typos in your script, all the controls should work properly, but it may take a couple of clicks to synchronize their state with the state of their counterparts in the Render Scene dialog.To fix this, we need to add event handler code to our script that sets the check boxes to reflect the current state of the scene when quickDraft first opens. This event handler will not belong to any particular UI widget, but rather to the rollout itself. | 9. | Launch Visual MAXScript again, select the rollout itself, and go to the Event Handlers tab.The rollout has an open handler, which is called when the floater is first launched. We want to add code to the open handler that sets the state of each MAXScript check box to match the equivalent setting in the Render Scene dialog. UI elements are objects with properties, just like everything else in MAXScript, so setting the check box state is just a matter of reading the state of each parameter from the scene and assigning those values to our check box's .state property.By modifying the proof-of-concept code to read from, rather than write to, the values in the Render Scene dialog, we can create our open handler without much extra work. | 10. | Click the open handler, and then enter the following code in the Edit Event Handler dialog (the code is also on the DVD as quickDraft_open_handler.ms if you wish to cut and paste): hidden.state = rendHidden rfw.state = rendShowVFB save.state = rendSaveFile re = maxops.getCurRenderElementMgr() elements.state = re.getElementsActive() aa.state = renderers.current.antiAliasing samp.state = not renderers.current.enablePixelSampler shad.state = renderers.current.shadows area.state = rendSimplifyAreaLights rt = rayTraceGlobalSettings() raytrace.state = rt.enable_raytracing atmo.state = rendAtmosphere displace.state = renderDisplacements
| 11. | Use File > Save to write the code out to the script editor again, close Visual MAXScript, and save the script as quickDraft_interface04.ms. Pick File > Evaluate All to launch your current version.The utility should now reflect the current state of the render controls when first opened. zIf a previous iteration of the tool was open, you may have noticed that it stayed onscreen. | 12. | Ideally, we'd like the script to be smart enough to close an existing dialog when it's run again. We do this with a destroyDialog command at the very beginning of the script, on a blank line before the rollout definition: try(destroyDialog quickDraft_rollout)catch()
TRy() and catch() are extremely useful for all kinds of scripting tasks. When code is located inside a try() statement, any errors encountered will cause the code inside the catch() to be executed instead of MAXSscript halting with an error message. Since the catch() is empty in the above code, we are telling MAXScript to ignore any errors (such as there being no quickDraft_rollout dialog bar to destroy).Without the try()catch(), the entire script would fail if there weren't a quickdraft_rollout in the interface to remove. With it, the script will work, and work properly, regardless of whether we're opening a new floater or replacing an existing one. | 13. | Run quickDraft with and without a dialog bar already onscreen to make sure that the old dialog bar is removed properly. You may have to move the old one to see it disappear.There's just one more step. We need to add a few lines to turn our code into a macroScript. MacroScripts contain extra information that allows them to be assigned to keystrokes, toolbar buttons, and quad menus, and they carry the file extension .mcr instead of .ms.When you run a macroScript, the script code is not executed immediately. Instead, a slightly modified copy of it is created in your UI/MacroScripts directory, and the scripted tool becomes available in the Customize User Interface dialog so that you can make it a regular part of the UI. In fact, a great many of 3ds max's built-in tools are actually macroScripts.Note | If you want to alter a macroScript that already exists in your UI/MacroScripts folder, edit a copy of the .mcr file in another directory and then run it from the MAXScript menu in order to update the "live" definition. This will ensure that UI elements based on the original macroScript maintain their connection after the update. |
| 14. | Add the following code to the very beginning of the script: macroScript quickDraft Category:"Render" Tooltip:"quickDraft" (
This means that the script will appear as a new tool, labeled quickDraft, in the Render category of the Customize User Interface dialog.Since we added an open parenthesis to the beginning of the script, we have to close it at the end to make MAXScript happy. To the very end of the script add the following: )
| 15. | Save your macroScript as quickdraft_final.mcr. | 16. | Choose MAXScript > Run Script, browse to your saved quickdraft_final.mcr, and click Open. Nothing appears to happen, but this step makes quickDraft available as a command in the Customize User Interface dialog. A finished version of the script is also on the DVD as quickdraft_final.mcr. | 17. | Choose Customize > Customize User Interface, go to the Quads tab, and choose Render in the Category menu. Find quickDraft in the Action menu, and drag it to a comfortable spot in your default Viewport Quad Menu. | 18. | Close the Customize User Interface dialog, and right-click in a viewport. Choose quickDraft in your quad menu to launch your script. |
Congratulations! You've just designed, proofed, written, tested, debugged, and installed your very own MAXScript utility. The principles and techniques you used to create it are applicable to almost anything in the interface that you find yourself reaching for on a regular basis.colorClipCreating a Dockable Toolbar There are times when even the tiniest floater is too much clutter in the interface. Since max 5, scripters have been able to create dockable toolbars from their rollouts. These can contain any of the UI elements available in MAXScript but fit neatly into the interface like a regular max toolbar.In the next few pages, we'll create a simple replacement for the stock Color Clipboard utility that's buried in the Utilities panel, creating a modeless one that fits neatly next to max's main toolbar instead. As with quickDraft, the impetus for creating this script is to save trips to out-of-the-way parts of the interface and to speed up workflow.Design Considerations In order to fit our UI widgets into a toolbar, we're going to have to pay close attention to size, so that the toolbar's height matches that of the toolbars it will be docked with. We also don't want to have too many controls, as there might not be much extra room in the UI to dock in, especially at lower resolutions.Let's build our toolbar with six color swatchesa good compromise between size and utility.One easy part of this script is that drag-and-drop functionality is hardwired into colorPicker UI elements; the color swatches need no event handler code, so there's no proof-of-concept work to do.Writing the Script Without any proofing to do, we can dive right in. Finding the right values for a clean layout can be a lengthy process of trial and error, so they are provided for you.Note | Toolbars' size requirements vary depending on your Use Large Toolbar Buttons setting (found in the General tab of Customize > Preferences). The values used in this exercise will fit small toolbars.If you use large buttons, use four color swatches instead of six, a rollout height of 39, a rollout width of 152, an X spacing of 32 between swatches, and a colorPicker width and height of 32 instead of the values given below.A completed version of the script written for large icons is included on the DVD as colorClip_large.mcr. |
1. | Open a new MAXScript Editor, and choose Edit > New Rollout to start Visual MAXScript. | 2. | Enter the following parameters in the rollout's properties sheet:name: colorClipcaption: Color Clipboardwidth: 160height: 30 | 3. | Create a colorPicker UI element in the rollout. Size and placement aren't important, since we'll be setting those by hand. | 4. | Set the following properties on the colorPicker's Properties Page:caption: delete the default caption, leaving the property blankx-pos: 2y-pos: 3width: 20height: 20color: (color 128 128 128) | 5. | Copy and paste the colorPicker five times, manually setting the x-pos property to the following each time: 26,50,74,98,122. Make sure to keep the y-pos property at 3 for all the swatches. Your layout should look like that shown in Figure 6.9. The extra horizontal space is to accommodate the toolbar handle that will appear when you dock the script floater.Figure 6.9. Laying out the Color Clipboard toolbar in Visual MAXScript.
 | 6. | Write your UI code to the Script Editor with File> Save, then close Visual MAXScript. | 7. | Save your script as colorClip_layout.ms. | 8. | Now let's add the macroScript header, closer, and dialog declaration as we did for quickDraft. To the beginning, add: macroScript ColorClip Category:"Color Clipboard" Tooltip:"Toolbar Color Clipboard" ( try(destroydialog colorClip)catch()
and to the end add: createDialog colorClip width:160 height:30 style:#(#style_toolwindow) escapeEnable:false )
| 9. | In order to make the dialog dockable, we need two more lines of code. At the end, between the createDialog line and the last parenthesis, add as a single line the following:[View full width]cui.registerdialogbar ColorClip style: #(#cui_dock_horz,#cui_floatable,#cui_handles)
minsize:[160,30] maxsize:[160,30]
This line of code tells max to treat our dialog floater as a dockable toolbar. | 10. | At the beginning, between the first open parenthesis and the destroyDialog line, add: try(cui.unregisterdialogbar ColorClip)catch()
This code is necessary because in order to get rid of a dockable dialog bar, it must first be turned back into a regular dialog bar with cui.unRegister DialogBar so that destroyDialog can act on it. Just one of those things. | 11. | Save your script as colorClip_complete.mcr. | 12. | Register the macroScript by choosing MAXScript > Run Script and browsing to the location of your saved script (or colorClip_complete.mcr on the DVD). | 13. | Open the Customize User Interface dialog and assign the newly minted command to launch the Color Clipboard to a toolbar or quad (Figure 6.10).Figure 6.10. Assigning the Color Clipboard macroScript to a quad menu.
 | 14. | Launch the Color Clipboard toolbar and test it out (Figure 6.11).Figure 6.11. The Color Clipboard toolbar in action.
 |
|