How to make a skin from scratch
Today we'll talk about creating your own custom skin.
If you've played with Plug'n Script for some time already (learned how to make a custom .kuiml layout for your script at least), then you probably start thinking about how to make the whole plugin look different from a traditional Blue Cat Audio design.
This skin is beautiful, but how to get rid of the top menu, for example?
If we try to edit this default skin (the base file is "default.xml" in the Skins directory inside the PnS plugin), we'll find out that it's quite hard to modify it without getting loads of errors, because different parts of the default skin depend on each other.
Probably the best option is just use LM_Skin, which allows deep customization and has loads of possibilities. But if not LM_Skin, what do we do? How do we make our own skin for Plug'n Script?
Essential plan
- Create a basic layout
- Add toolbar with typical commands (menu/undo/redo/presets/zoom etc) and a status bar with a log
- Add some controls (for a particular script)
This is good if we make a skin for a particular (exported) plugin. If we want to make a skin that works well for Plug'n Script, we'd also have to do this:
Advanced plan
- Support loading and editing different scripts
- Add proxy-parameters (like "custom_paramY") to dynamically map dsp.inputX parameters for scripts
- Auto-create GUI for the scripts that don't have custom .kuiml
This is where we'll stop, otherwise we may never stop.
In fact, you would also need a routine for plugin exporting, maybe some customization options, maybe some built-in controls, maybe resizing support, misc development helpers, the list goes on, and it's hard to stop enhancing it. But we'll leave that time-consuming tasks for now and concentrate on what we've planned.
1. Create a basic layout
Go into the user skins folder (the path on Windows and Mac is similar):
/Users/[YourName]/Documents/Blue Cat Audio/Blue Cat's Plug'n Script/Skins
And create a new .xml file
hello_world.xml
with the following content
- <?xml version="1.0" encoding="utf-8" ?>
- <SKIN refresh_priority="idle" font_size="16" font_size_mode="character" background_color="#D7CEC7">
- <CELL id="root_cell" min_width="400" min_height="300">
- <!-- TOOLBAR -->
- <TEXT value="Title" />
- <!-- BODY -->
- <TEXT value="Hello world" />
- <!-- STATUSBAR -->
- <TEXT value="GUI Loaded" />
- </CELL>
- </SKIN>
This is a good place to start. We've just set a few attributes for the SKIN element regarding font_size and background_color, and also some more technical attributes that define font rendering (font_size_mode) and overall GUI performance (refresh_priority). In practice these two better be always set like in this example.
We've also added an additional root CELL element with mininal width and height. This is not neccesary, as we could set them in the SKIN element as well, but sometimes it's nice to have a root CELL to manipulate it later. For example, it'll allow you to read and change plugin window size. For that case we've given this CELL an id ("root_cell") which is also totally optional.
The next thing we need is the way to reload the skin after we make changes. One of the ways is to switch to another skin and back, but this is not very convenient (obviously). Still we'll have to do it at least next time.
Reloading the skin
Because there's no built-in action to do that, we'll use a trick to slightly change GUI zoom parameter, which will trigger full skin reloading.
- <!-- button and action to reload the skin -->
- <SYSTEM_ACTION_BUTTON action_id="reloadSkin" />
- <ACTION id="reloadSkin" name="Reload" type="Script"
- script="if ((gui.zoom-floor(gui.zoom))>0.00001) gui.zoom = floor(gui.zoom); else gui.zoom=gui.zoom+0.000001;" requires="gui.zoom" />
Switch to another skin and back to this one, and you should see the "Reload" button, which will make our further development easier. Notice that we've added a SYSTEM_ACTION_BUTTON which displays a standard button on Windows or Mac, and created an ACTION that this button will trigger. As you see it doesn't matter if that ACTION is defined before or after the button.
Now let's make a proper toolbar and status bar.
For the toolbar we'll use:
and for the status bar:
We use WIDGET element because it has a "background_color" attribute which we need, otherwise CELL or ROW would be just fine.
For the moment everything is centered in our GUI, but we want the "body" to take all the free space. For that we use a "flex" attribute, which will do exactly that. Also we slightly reorganize the status bar.
- <?xml version="1.0" encoding="utf-8" ?>
- <SKIN refresh_priority="idle" font_size="16" font_size_mode="character" background_color="#D7CEC7">
- <CELL id="root_cell" min_width="400" min_height="300">
- <!-- TOOLBAR -->
- <WIDGET layout_type="row" background_color="#76323F" text_color="#FFFFFF" font_size="20" width="100%" height="37" >
- <TEXT value="Hello world" />
- </WIDGET>
- <!-- BODY -->
- <WIDGET layout_type="row" flex="1" background_color="#D7CEC7" min_width="100%">
- <TEXT value="This is a nice place to start" />
- </WIDGET>
- <!-- STATUS BAR -->
- <WIDGET layout_type="row" background_color="#565656" text_color="#FFFFFF" width="100%" height="35" margin="7">
- <CELL flex="1">
- <TEXT value="GUI Loaded" h_align="left" />
- </CELL>
- <!-- button and action to reload the skin -->
- <SYSTEM_ACTION_BUTTON action_id="reloadSkin" />
- <ACTION id="reloadSkin" name="Reload" type="Script"
- script="if ((gui.zoom-floor(gui.zoom))>0.00001) gui.zoom = floor(gui.zoom); else gui.zoom=gui.zoom+0.000001;" requires="gui.zoom" />
- </WIDGET>
- </CELL>
- </SKIN>
This is where we are now.
Okay, the basic layout is ready! Let's move on to the next chapter.