Modern Skin: Maki Overview

From Winamp Developer Wiki
Jump to: navigation, search

Creating a Modern Skin --> Intro --> Winamp 2 to Winamp 3+ --> Simple Skin Tutorial --> XML Intro --> Simple Skin Tutorial (Continued) --> Container --> Group --> Relative Positioning --> Complex Skin --> Non-Rect Player --> Layer Composition --> Alpha Channels --> Animatedlayer --> Snap Points --> Drawers --> Skin Scripting --> Drawer Scripting --> Animating a Skin --> Maki Overview --> Glossary


What is Maki

Maki is a user interface and event management scripting system and more. The primary purpose of Maki is to handle all of the user interface behavior. Maki is used to insert functionality in Winamp3. The inserted functionality can range from a new user interface behavior to an alarm clock to a seperate EQ control system. You must not forget that Maki is part of Wasabi, which is used to build Winamp3. It's therefor safe to assume that Wasabi based applications (other than Winamp3) support Maki also. Well, when there are others that is.


What does Maki mean?

Make A Killer Interface


What can Maki do?

Maki as a language can do pretty much everything most scripting languages do. It supports user functions, user classes. It also has a full fledged pre-processor that allows you to include other Maki source files. Maki scripts are actually compiled using the Maki Compiler (MC.EXE, look for it in your Winamp3 directory. Don't worry about the compiler, we'll explain how it works later on).

So here's a list of what Maki can do, just remember, it might change, but always in a good way, at least, we hope so.

  • Trap and hook events (onClick() do something...)
  • Move user interface elements (take button A and move it to position x,y)
  • Move and change images (button A has image A, set button A's image to image B)
  • Show and Hide Windows.
  • Control Winamp3 playback (play, stop, next, etc.)
  • Control Winamp3 volume (set the volume to 100%)
  • Control Winamp3 equalizer levels (set 60hz to +20db, for you bass addicts.)
  • Make an Alarm
  • Make a Clock
  • etc.

Now, you might not realise it, but the fact it can trap events and hook events and create new GUI objects on the fly means it can pretty much do anything. Something very important to remember is that some GUI objects need to be "binded" before being able to be used to trap events. The best way to go about this is to remember that objects need to be binded before being used. Here's a short example:

Global Timer myTimer;
System.onScriptLoaded() {
myTimer = new Timer;
}
myTimer.onTimer() {
//Do cool stuff here.
}


When should I use Maki?

It's always hard to decide if you want to implement something via scripting or component. Always remember that many things can be done with Maki and that implementing something via scripting is also much faster than using a component. This is super true when it comes to user interface behavior in skins. Literaly ANYTHING that has to do with how the user interface (skin) behaves and changes because of user input is pretty darn quick to write in scripting, but you can still do it in a component if you wish.

Mainly, you have to look at the potential level of complexity of what you're trying to do. You don't want to implement something very complex in script because it will definitely be slower than straight C++ code.


Maki Syntax

Here's where the fun ends for me and I have to start being all serious and actually explain important stuff. Ugh. So, first I'm going to explain general syntax, like what constitutes an instruction, how you terminate lines, etc. Then we'll jump into variables, functions, classes and class members. Here we gooooooooo!

First off, Maki is NOT case sensitive, so a function named llama can also be called by using Llama. I'd also like to point out the difference between pre-processor statements and actual code statement. Pre-processor statements are read and processed FIRST, before even ONE shred of code is actually compiled. They start with # and end with a carriage return. Actual code starts pretty much with anything but # and ends with a ;. This excludes flow control statements (like if(..) {... ). Now I know it's a bit odd to just read things and not see it, so, how about a little example? *nod*

First, pre-processor statements:

#include "../../lib/std.mi"

#define ACTIVEALPHA   (230)
#define INACTIVEALPHA (150)

The pre-processor statements are pretty self explainatory. I'll explain what they actually mean really soon, just observe the syntax for now.

Now, a code snippet:

if (isactive != prev_active) {
prev_active = isactive;
fader.start();
}

Since if is a control statement and marks the beginning of a code block ( a code block is something in between { .. } ), it doesn't require a ;, the line below it however, isn't a control statement and requires the line to end with a ;. Again, I will explain what everything means later, for now, just observe the syntax.


Maki Datatypes

In this section, we'll go thru all the different datatypes available in Maki and how to use them (And also, a quick overview of what exactly is a variable in Maki). Currently in Maki there are 6 basic types you can use:
  • Boolean
  • Int
  • Float
  • Double
  • String
  • Object*

* Object is a compound type, we'll see what it means later.

Now for a description of each of the types. Please note that the variable types aren't case sensitive.

Boolean

Boolean is a boolean value that can have two states. For us, these states are true (1) and false (0). Here's how you create a Boolean variable and assign a value to it:

//Create a bool type variable and assign 0 (false) to it.
Boolean state = 0;
//Assign 1 (true) to our bool variable named state.
state = 1;
//Assign false (0) to our bool variable named state.
state = false;
//Assign true (1) to our bool variable named state.
state = true;

Int

Int is a signed* round integer value from -2 147 483 647 to +2 147 483 648 (this means no decimal values, ever). Here's how you create an Int variable and assign a value to it:

//Create an int type variable and assign 255 to it.
Int alpha = 255;
//Assign the value 1000 to our int variable named alpha.
alpha = 1000;
//Assign the value -1000 to our int variable named alpha.
alpha = -1000;


Float

Float is a signed floating point number. Here's how you create a Float variable and assign a value to it:

//Create a float type variable and assign 0.25 to it.
Float fraction = 0.25;
//Assign the value 0.5 to our float variable named fraction.
fraction = 0.5;
//Assign the value -3.5566 to our float variable named fraction.
fraction = -3.5566;


Double

Double is a signed floating point number with double precision.

//Create a float type variable and assign 0.000000125 to it.
Double fraction = 0.000000125;
//Assign the value 0.5 to our double variable named fraction.
fraction = 0.5;
//Assign the value -3.5566 to our double variable named fraction.
fraction = -3.5566;

String

String is a string, it can be of any length. Here's how you create a String variable and assign a value to it:

//Create a string type variable and assign a sentence to it.
String name = "My real name is not Aus.";
//Assign the value "Guru" to our string variable named name.
name = "Guru";
//Assign the value "Francis" to our string variable named name.
name = "Francis";

Object

Object is a compound type. This means it can have more than just one value associated with it. Infact, you can even attach values to it, and even other objects.

Null

Null is a special case. You can't create a variable of this type, it is ONLY used in comparaisons and can compare to any type variable and object. You can use it to see if a variable contains something or exists.

Maki Operators

Mathematical

All basic math operators are available, here's a list of them and what they do.

File:Table1.png


Logical

File:Table2.png


Bit

File:Table1.png


Assignment

File:Table1.png

Maki Control Structures

Control structures are what influence the flow of the code, certain parts are executed only in certain cases, some a fixed amount of times, some a variable amount of times, etc. Most of the basic control structures found in modern languages are available in Maki. Here's a list of them:

if

if(state == true) {
	state = false;
}

if else

if(state == true) {
	state = false;
} else {
state = true;
}

while loop

while(state == true) {
...
}

do while loop

do {
	...
} while(state == true);

for loop

for(int i = 0; i < 10; i++) {
	...
}

Maki Functions

How do I create my own Maki functions

Functions in Maki need to be declared before they can be used (you can declare and define it if you want also). When declaring a function you need to use the proper prototype line for the function you wish to create. This includes the return value type and the parameters it takes.

There are two ways you can go about creating functions.

1) You can group all your function declarations (called prototypes) at the top of your script and then define (write the actual code associated with the functions) them anywhere in the file. Like so:

#include 

Function Boolean CheckLevel(int Threshold);
Function Int CheckPlaystring(String _Playstring);

...
Boolean CheckLevel(int Threshold) {
...
}
Int CheckPlaystring(String _Playstring) {
...
}

2) You can declare the function just before defining it. Like so:

#include 
...
Function Boolean CheckLevel(int Threshold);
Boolean CheckLevel(int Threshold) {
...
}


The preferred method is the first because it's just much easier to organize things, but, you can do it the other way if you want to.

How to read function prototypes

Function RETURN_VALUE_TYPE FUNCTION_NAME(PARAM_TYPE PARAM_NAME, ...);

  • RETURN_VALUE_TYPE is the type of the return value, it can be any type supported by Maki, including user classes.
  • FUNCTION_NAME is the name of the function you are declaring. It can be any combination of letters and numbers but it MUST start with a letter.
  • PARAM_TYPE is the type of the parameter you will be passing to the function, it can be any type supported by Maki, including user classes.
  • PARAM_NAME is the name the parameter will have inside the function, it can be any combination of letters and numbers but it MUST start with a letter.


The function's name and parameter names CAN NOT use any of the existing Maki keywords.

Maki Classes

The already existing Maki classes usually consist of two things: member data and methods. It's very important to remember that user classes do not support methods yet. (needs improvement)


Maki User Classes

(needs improvement)

Gerneral Scripting Rules

These are just general things you want to keep in mind when writing Maki scripts and when writing code in general too! :)

  • As a rule of thumb, all uppercase is reserved for constants. So please avoid naming anything that's not a constant all in uppercase.

STD.MI Reference

If you'd like to know more about STD.MI simply open it in your favorite text editor and check out the spiffy comments. If you need more help, check out the forums!