Skip to content

Introduction to Squirrel Programming

liquid8d edited this page Jun 15, 2015 · 15 revisions

#About Squirrel Squirrel is the scripting language built into Attract-Mode which allows users to extend the functionality of the frontend.

You can view some of the scripts used in the following folders on your Attract-Mode installation:

modules/
plugins/
layouts/

Some are contained in folders, but each of them use text files with the .nut extension which uses the Squirrel language format.

#Getting Started It's helpful to have some basic programming understanding, but isn't required. Since Squirrel is a programming language it has its own syntax in regards to variables, functions, objects and classes. We'll try to keep things simple here, but you can learn more about Squirrel at these links:

Squirrel 3.0 Reference Manual
Squirrel 3.0 Standard Library Manual

##Squirrel Syntax ###Variables A variable is a way to store a value or a reference to something in your script.

    local myInteger = 100;
    ::myString = "This is global";

A variable can be an integer (negative or positive number), a float (decimal number) a string (text), a boolean (true/false), arrays and tables (multiple values), functions (mini-script) or an instance to a class (a reference to an object).

Variable names should be short but understandable - usually with a lowercase first letter and uppercase for additional words or use all lowercase with an underscore (_) to separate words. There can be no spaces or most special characters.

Variables can be stored local to the script, or stored in the Squirrel root table using :: in front of the variable name to be access globally from any script.

Note that each variable line ends with a semi-colon as with most programming languages.

###Comments Code without comments is bad, mmkkaay? When you write a program, or script - you want to make sure you describe what you are doing. All programming languages provide a way to add comments to your code. For squirrel, there is a single line comment and multi-line comment:

//this is a single line comment

Just put double forward slash in front of your comment for a single line comment. This can even be after your semi-colon. As soon as Squirrel see the // it ignores the rest of the line as a comment.

/*
This is a multiple line comment.
We can go into more detail with this.
*/

Multi-line comments are started with /* and continue multiple lines until it reaches */ which ends your comment.

If you want to learn to code, or just make life easier when creating your layout - get in the habit of commenting! It helps in case you forget something, and even more if someone else is trying to figure out what you did!

###Functions A function is a way to separate a block of code that performs a certain function. You might make a 'debug' function that prints some text:

function debug( text )
{
    print( "Debug: " + text + "\n" );
    return true;
}

Functions can then be called anywhere else in the script, meaning you don't have to keep re-writing the code.

Functions can include variables that are passed to it allowing it to perform calculations. If desired, you can return a value from your function which can then be assigned to a variable.

A function can be on a single line, but is sometimes better to span across multiple lines for readability. A function does not have to have the semi-colon at the end of it.

Squirrel provides many useful built-in functions, for example the print( str ) function used above.

###Tables To store multiple values within a single variable, you can use what Squirrel calls a table.

local myTable = {
  firstValue: "This is the first value",
  secondValue: 100
}

A table begins with the opening curly brace and ends with the closing curly brace. Each item you include in the table will be a variable name, followed by a colon, then the variables value. If you include more than one variable, each one should be separated with a comma.

A table can be on a single line, but is sometimes better to span across multiple lines for readability. A table does not have to have the semi-colon at the end of it.

##Frontend Binding To interact with Attract-Mode from a Squirrel script, an fe table is made accessible to you in any .nut file you create. A table contains variables and functions that will be useful to you. For example, if you want to know the directory your script or layout is running from:

print( fe.script_dir + "\n" );

A full list of the functions and variables that can be found using fe can be seen at: Layout and Plugin Programming Reference

We will use the fe table as we go on, so you can reference that if you want to know more about a certain variable or function we use.

#Layouts Now that we understand a bit about Squirrel, we can start creating layouts. In a nutshell, a layout controls what objects are displayed on the screen and where, but they can do much more.

##First Steps Create a folder
Layouts are stored in your Attract-Mode folder in the layouts/ folder. All layouts should be in their own folder - the only exception is the screensaver.nut which is the layout file for the frontend screensaver.

Create a layout.nut file
For a layout to work, you must create a file named layout.nut in your layout folder. This is where we will write a script to describe our layout. Open your layout.nut file in any text editor. Any will do, but a list of recommended editors can be found here.

First, we want to make sure that our layout will work correctly regardless of someones resolution, so the first thing we will do is tell fe we want the layout to be a specific resolution.

In your layout.nut file add the following lines:

fe.layout.width = 640;
fe.layout.height = 480;

While you don't have to specify the layout width/height - it would default to your screen resolution which may be different for each user. This ensures that Attract-Mode will scale your layout for other users to fit the resolution that you designed the layout for.

The next thing we want to do is add some objects to our layout. At least one object must be added for a layout to be shown.

Using the fe table described above, Attract-Mode provides function to do exactly that:

fe.add_text( str, x, y, w, h );
fe.add_artwork( art, x, y, w, h );
fe.add_listbox( x, y, w, h);
fe.add_image( img, x, y, w, h );

We'll walk through adding each of these to your layout one by one.

##Text We'll start by adding a single text object that contains the game title. Add the following line to your layout.nut file:

local title = fe.add_text( "[Title]", 0, 10, fe.layout.width, 35 );

Here we running the fe.add_text function telling it the text we want, the x, y coordinates on the screen and the width, height of the text object. We assigned the result to the title variable. We used a special fe variable to set the width to the full width of our layout.

While we don't have to assign the functions result to a variable, this will allow us to access the text object further in our code.

Since we have the text object (title), we can now use the Attract-Mode functions and variables for a Text object. Add this line to your layout.nut:

title.set_rgb( 0, 255, 0 );

This will set the title text color to bright green ( 0 Red, 255 Green (max), 0 Blue)

Your layout.nut should now look like this:

fe.layout.width = 640;
fe.layout.height = 480;
local title = fe.add_text( "[Title]", 0, 10, fe.layout.width, 35 );
title.set_rgb( 0, 255, 0 );

Save your layout.nut file. Open Attract-Mode, hit TAB (for Settings), select your current Display and change the layout to the one you created (as named by the folder you created). Hit ESC to go back to your layout and you should see a single text line at the top-left of your screen. Using up and down this will change the current game.

A full list of what you can alter with a Text object can be found here.

That's it! You made your first layout. Just a text with the title isn't very fancy. Let's spruce it up.

##Artwork Attract-Mode makes displaying artwork easy by having the user specify their artwork folders. By default for Mame: the flyer, marquee, snap and wheel folders are supplied asking the user to tell it where the artwork for each is. More can be added, though!

Let's add the snap artwork to our layout. Add the following to your layout.nut:

local snap = fe.add_artwork( "snap", 338, 70, 287, 214 );

Notice we specified the "snap" artwork. We set it to some pretty specific sizes here - you'll see why later. Basically though, the snap x (338) is set a little past the center of the 640 width layout, and snap y (70) down a bit from the top (so it won't overlap with the title).

Your layout.nut should now look like this:

fe.layout.width = 640;
fe.layout.height = 480;
local title = fe.add_text( "[Title]", 0, 10, fe.layout.width, 35 );
title.set_rgb( 0, 255, 0 );
local snap = fe.add_artwork( "snap", 338, 70, 287, 214 );

Save your layout.nut and open Attract-Mode again. You should now see your snap or video of the selected game. If you don't, make sure you have the correct location for the snap artwork path in your Emulator configuration.

A full list of what you can alter with the Artwork object can be found here.

##Listbox A Listbox creates a simple list of games that can be navigated in our layout. . Add the following lines to your layout.nut:

local list = fe.add_listbox( 9, 75, 311, 385 );
list.rows = 20;
list.charsize = 16;

Again we have some specific sizes here. x is a little off the left side, y is a bit down from the top (not to overlap with the title), and the width and height makes it fit in the lower left side of the layout.

We are also setting some listbox variables - rows is how many games will be displayed in the list, and charsize is the font size of each text item.

Save your layout.nut file. It should now look like this:

fe.layout.width = 640;
fe.layout.height = 480;
local title = fe.add_text( "[Title]", 0, 10, fe.layout.width, 35 );
title.set_rgb( 0, 255, 0 );
local snap = fe.add_artwork( "snap", 338, 70, 287, 214 );
local list = fe.add_listbox( 0, 50, 300, 590 );
list.rows = 20;
list.charsize = 16;

A full list of what you can alter with the ListBox object can be found here.

##Image Artwork images are automatically found from the path provided by the user - but you can add any image to your layout.

We'll add a background image to the layout. BUT - we have to be careful. Objects in Attract-Mode are drawn in the order that you add them in your layout. This means if we add a background image AFTER our other objects, it will be drawn ON TOP. Since we don't want that - at least for now :) - we will add this line ABOVE all the other objects. Add these lines above your title object in your layout.nut:

local bg = fe.add_image( "bg.png", 0, 0, fe.layout.width, fe.layout.height );
bg.set_rgb( 0, 100, 230 );

This will now look for a 'bg.png' file in your layout folder. If it doesn't exist, the image won't show up. You can use this bg.png file I created just for this layout or you can add your own. You can change the filename if you want. But make sure to copy it into your layout folder.

We also set the color on the image. Yep! Any grey-scale colors will be altered based on the color you put.

Your layout.nut file should now look like:

fe.layout.width = 640;
fe.layout.height = 480;
local bg = fe.add_image( "bg.png", 0, 0, fe.layout.width, fe.layout.height );
bg.set_rgb( 0, 100, 230 );
local title = fe.add_text( "[Title]", 0, 10, fe.layout.width, 35 );
title.set_rgb( 0, 255, 0 );
local snap = fe.add_artwork( "snap", 338, 70, 287, 214 );
local list = fe.add_listbox( 9, 75, 311, 385 );
list.rows = 20;
list.charsize = 14;

Save your layout.nut file and run Attract-Mode again. Now you should see all your objects, with a background!

##Wrapup Now we have a pretty functional layout. Let's add a couple finishing touches:

List selected background color
The default background color for our list doesn't match the green that we used for our background, so we'll change it:

list.set_selbg_rgb(30,180,30);

Add a Marquee
If you used the bg.png provided here, you'll notice there is an open space for an image or text. Let's add another artwork at the end of your layout.nut file:

local marquee = fe.add_artwork( "marquee", 338, 303, 287, 75 );
marquee.preserve_aspect_ratio = true;

We'll also use a special variable called 'preserve_aspect_ratio' which makes the image fit in our specified size, but doesn't stretch it.

Add Information Text
Finally, we'll add some text information right below the marquee:

fe.add_text("[DisplayName]", 338, 385, 300, 20);
fe.add_text("[FilterName]", 338, 405, 300, 20);
fe.add_text("[ListEntry] of [ListSize]", 338, 425, 300, 30);

I didn't set these as variables, because I'm not changing any of their properties. Notice all of our text uses special strings enclosed in brackets. This means Attract-Mode will fill in the correct information when you go through your games. You can put your own text in there if you want, or combine multiple Magic Tokens with regular text.

Intro Layout

Hey! Looks pretty good. Play around with some of the objects properties until you have everything the way you like. You can remove any of the objects we put in, or add more if you want.

Next we'll get to some more advanced stuff.

##Additional Squirrel TODO:

  • arrays
  • if/elseif/else
  • for/foreach
  • switch/case

##Config Layouts can have configuration options that the user can change under 'Layout Options' when using your layout. These can be added in your layout.nut in a special format:

class UserConfig </ help="Intro Layout Options" />
{
	</ label="Color", help="The theme color", options="Green,Red,Blue" order=1 />
	color="Green";
}

The config creates a class that will contain user settings - with specific syntax to describe the help text and each configuration option. Notice each description starts with </ and ends with />. The help description immediately following UserConfig is the help text that shows at the bottom of the LayoutOptions screen when no option is currently selected. Each option is described within the curly braces.

When adding options there is certain information you can provide:

  • label: The name of the option, displayed in Layout Options
  • help: The help text shown at the bottom of the Layout Options screen
  • options: User selectable options. Each option should be followed by a comma, no spaces. This is optional. If it is not provided, the option will be a text input for the user
  • order: The order this option will shown in the Layout Options screen

Immediately following the description of our option - we specify a variable with it's default value. We will be able to find out later what the user has set this to, and make changes in our layout based on that.

Above, we have added an option for theme color to our layout. If you remember before, we set the background image color - and we're going to make that an option for the user.

Copy the above code at the top of your layout.nut file.

Save your layout.nut and start Attract-Mode. Hit TAB, select your Display and go to Layout Options. You should now see the option we added. Changing it won't do anything yet, we have to add some code for that.

Back in your layout.nut, remove the lines with bg.set_rgb(), title.set_rgb, and list.set_selbg_rgb().

At the end of your layout.nut, add these lines:

local config = fe.get_config();
if ( config["color"] == "Red" )
{
   bg.set_rgb( 170, 10, 50 );
   title.set_rgb( 255, 0, 0 );
   list.set_selbg_rgb( 180, 30, 30 );
} else if ( config["color"] == "Blue" )
{
  bg.set_rgb( 50, 10, 170 );
  title.set_rgb( 0, 0, 255 );
  list.set_selbg_rgb( 30, 30, 180 );
} else {
  //default to Green
  bg.set_rgb( 10, 170, 50 );
  title.set_rgb( 0, 255, 0 );
  list.set_selbg_rgb( 30, 180, 30 );
}

To access the color variable we put in the user config, we have to get the current settings with fe.get_config(). The get_config returns table with multiple values, which we will store in the config variable. To get get the color value, we use config["color"].

Next, we add an if statement. An if statement can check if something is true or something equals a certain value. Let's break it down:

  • if our color config value equals (==) "Red", then we will set the color variables on our bg, title and list to red colors

  • else if that is not the case, but it IS "Blue", set color variables to blue

  • else (not "Red" or "Blue"), use the default "Green" and set it to green colors.

Now, if a user has set their color Layout option to Blue, it will go through the if statement and set the colors correctly.

Here's what your layout should look like at this point:

class UserConfig </ help="Intro Layout Options" />
{
	</ label="Color", help="The theme color", options="Green,Red,Blue" order=1 />
	color="Green";
}

fe.layout.width = 640;
fe.layout.height = 480;

local bg = fe.add_image( "bg.png", 0, 0, fe.layout.width, fe.layout.height );

local title = fe.add_text( "[Title]", 0, 10, fe.layout.width, 35 );
title.set_rgb( 0, 255, 0 );

local snap = fe.add_artwork( "snap", 338, 70, 287, 214 );

local list = fe.add_listbox( 9, 75, 311, 385 );
list.rows = 20;
list.charsize = 14;
list.set_selbg_rgb(30,180,30);

local marquee = fe.add_artwork( "marquee", 338, 303, 287, 75 );
marquee.preserve_aspect_ratio = true;

fe.add_text("[DisplayName]", 338, 385, 300, 20);
fe.add_text("[FilterName]", 338, 405, 300, 20);
fe.add_text("[ListEntry] of [ListSize]", 338, 425, 300, 30);

local config = fe.get_config();
if ( config["color"] == "Red" )
{
   bg.set_rgb( 170, 10, 50 );
   title.set_rgb( 255, 0, 0 );
   list.set_selbg_rgb( 180, 30, 30 );
} else if ( config["color"] == "Blue" )
{
  bg.set_rgb( 50, 10, 170 );
  title.set_rgb( 0, 0, 255 );
  list.set_selbg_rgb( 30, 30, 180 );
} else {
  //default to Green
  bg.set_rgb( 10, 170, 50 );
  title.set_rgb( 0, 255, 0 );
  list.set_selbg_rgb( 30, 180, 30 );
}

That's it! We made a pretty neat Layout Option. You can make other options that the user can setup - and then change your layout based on user preferences creating a flexible layout.

##Sound

##Orientation

##Callbacks

###Transition Callback

###Tick Callback

Modules and External Scripts

TODO:

  • fe.load_module()
  • fe.do_nut()

##Advanced Squirrel (Part 2) class

#Plugins Coming Soon

#Modules Coming Soon