Home Automation EZine
EMagazine
Volume 10 Issue 2
Apr / May 05

Features

Cover Page

Custom-Designed Home Theater

Total Room Home Theater

How to Wire Your Home Systems

Serious Sound System

HDCP: For Better
or for Worse?

The Home Technology Integrator

The Art of Tuning

DVD Insider

Alternative Big-Screen Displays

Projection Screens 101: How Big?

Gibson’s Wurlitzer Digital Jukebox

Mainstream Market for Home Control

PLC and Grafik Eye

Installing A Doorjamb Light Switch

Create Media Center Apps With Meedio

Wireless Sensor Network

Absolute Power Sells….Absolutely!

Power Protection in the Home Theater

To Be Wired Or Not To Be!

An X-10 Broadcast Car Monitor

The Oyaide Advantage

Miniature Stereo Amplifier

Wireless Comm Between PC and Sewing Machines

New Projection Screen Breakthrough

Your Home Will Call You When a Problem

Motorized Ceiling Projector Lift

Secure Your Cottage

Dashboard for Communication

Interviews

Raoul Wijgergangs Zensys

Stephen Street
StreetFire Labs

Reviews

AViC Cable

Return to Main Menu
Home Toys Article
- April 2005 -
[Home Page]

[Click Message To Learn More]

How to Create Media Center Applications With The Meedio Platform
by Pablo Pissanetzky, CTO,
Meedio LLC

Creating applications with a "10-foot" interface is as easy as Tic-Tac-Toe when you're working with the right tools.

Meedio

Introduction

Ever since the advent of myHTPC in early 2003, PC and home theater enthusiasts have been searching for ways to integrate emerging technologies with their entertainment systems. Early HTPC (Home Theater PC) communities grew up around the idea of extending HTPC software with "plugin" applications. Unfortunately, most HTPC applications were never designed with a true plugin architecture in mind, and so the few plugins that were developed were usually little more than separate programs that could be launched from the main front-end application. When the development of Meedio started towards the end of 2003, one of the main design principles that the HTPC community requested was an architecture that supports native plugins which truly integrate with the host platform. Meedio met this challenge with a solution that is not just a digital media center application, but an entire platform for creating new applications. In fact, it is so easy to create powerful new applications with Meedio that in the eight months since Meedio Essentials was released, over 180 plugins have been published in the Meedio Add-Ins Directory.

This tutorial will walk you through the whole process of creating a Meedio plugin. We will be using Windows Script Components and VBScript, so all you will need is Meedio and Notepad. We will cover the creation of the plugin description file, the code for the plugin, a new screen and finally the creation of a Meedio Plugin Package to distribute the plugin.

Note: You may need to install Windows Script 5.6 (http://msdn.microsoft.com/library/default.asp?url=/downloads/list/webdev.asp), especially if you are not running Windows XP.

Describing the plugin

In order for Meedio to recognize and understand your plugin, you must first create a plugin description file. These files have the .plugin extension and are simple XML files; they contain basic information about your plugin such as its name, type, documentation, the name of the author and such. You can easily create them using Notepad but, fortunately, Meedio provides a tool to help us create .plugin files. This tool is called PluginEditor.exe and it is located in the Meedio installation directory.

So, our first step will be to use the plugin editor to create our .plugin file. Double click on PluginEditor.exe.

First of all, we set the name of the plugin; it is the name by which the plugin will be known to everyone. Secondly, each plugin must have a unique identifier, also known as the plugin ID. Meedio dictates that this must be a GUID (Globally Unique IDentifier). It is not important for us to understand this completely; just know that it is a way to identify your plugin from all others. You can click the "Generate ID" button to create a new ID for your plugin. Note that this only has to be done once, when you first create the plugin. After that, its ID will remain the same forever.

Then, we enter the version and the status. The type of our plugin will be "Module", which means that users will be able to add it to their Meedio menu structure and it will be launched by Meedio only when the user clicks on it. We also set the module type to "Module" to signify that it is a simple module; most plugins are. Finally we enter a short description.

Now, we move on to the details tab. Here, we must specify the name of the folder where the plugin will be installed. We do not need to enter a full path, as Meedio will figure that out automatically, but we should pick a fairly unique name that describes our plugin. We must also tell Meedio what the main file of our plugin will be. This is the file that contains the code for our plugin. Since we are using Windows Scripting, we will be creating a .wsc file that will contain the code for the plugin in the next section.

The plugin description file also lets you include some documentation about the plugin. You can either type it into the box or include it in a separate file (such as an HTML page) that will be packaged with your plugin later. Our plugin is so simple that we won't need to include extensive documentation.

In the author tab we put some information about ourselves (me, in this case). The download url is optional and should only be used if you do not want to publish your plugin on MAID, but would rather have users download it directly from your site.

Finally, in the license tab, we choose the license type and put in a copyright message. Note that MAID does not enforce the license types; they are in place merely for documentation purposes.

We are now finished entering all the required information...whew! It is time to save the .plugin file. To do this, simply click on the "File" menu and select "Save as...". To make things easier for us, we will intentionally save the file to the folder where Meedio is expecting it. In this case, it should be:

<meedio installation dir>\plugins\module\TicTacToe\TicTacToe.plugin

This path is a combination of the base directory for plugins (<meedio installation dir>\plugins), the plugin type (module) and the destination folder (TicTacToe) we specified for the plugin. The actual file name is not important, as long as it has the .plugin extension, but it is good practice to use the name of the plugin as the file name.

If we open the file with Internet Explorer, we see its contents. All the information we entered is there.

This concludes the first section. We have created the .plugin file which serves two main purposes: 1) it lets Meedio find and understand your plugins and 2) it lets MAID list the plugins with a fair amount of information. You can also use the Plugin Editor to update your plugin files. For example, when you make a new release, you need to increase the version number of your plugin, which you can easily do with the Plugin Editor.

Creating the skeleton code

In this section, we will create the basic skeleton for the plugin code. This includes the methods necessary for Meedio to execute the plugin. When we are finished with this section, the plugin will not actually do anything, but we will be able to test that Meedio can load it to ensure we have done everything correctly.

This step will vary greatly depending on the programming language you are using to create your plugin, but we provide downloadable skeleton code for the most popular languages in the Plugin Documentation page.

Since we will be using Windows Script Components to create the Tic Tac Toe plugin, we will need to create a .wsc file with the skeleton code. Simply run Notepad and type the following into it. (Or, just copy and paste it).

<?XML version="1.0"?>
<component>

 
<registration
 
  description="TicTacToe Meedio Plugin"
 
  clsid="{91E2DE7A-C331-4EAF-920A-D39B606FC2B2}"
 
  version="1.00">


 
</registration>
 
<implements id="Automation" type="Automation">
 
  <method name="OnMessage"></method>

 
  <method name="EditCustomProperty"></method>
 
  <method name="GetProperty"></method>

 
  <method name="SetProperties"></method>
 
</implements>
 
<script language="VBScript">

 
<![CDATA[
 
'.........................................................................
 
function OnMessage( Sys , Msg )
 
  OnMessage = vbTrue
 
end function
 
'.........................................................................
 
function EditCustomProperty( Window , PropName , Value )
 
  EditCustomProperty = vbTrue

 
end function
 
'.........................................................................
 
function GetProperty( Index , Prop )
 
  GetProperty = vbFalse
 
end function
 
'.........................................................................
 
function SetProperties( Properties , ErrorText )
 
  SetProperties = vbTrue

 
end function
 
'.........................................................................
 
]]>

</script>
 
</component>

Windows Script Components are written inside an XML file with a .wsc extension. This file contains some basic information about the component and then the actual code for it.

There are a few important things to note here. First of all, for the clsid attribute inside the registration element, it is very important that you use the same value that was used for the plugin ID in the first section of this document. You can simply copy the value from the Plugin Editor and paste it there. This means that our plugin will be registered using the same identifier. If it is not, Meedio will not be able to execute it.

The contents of the implements element must be as they are shown above. This element describes the "methods" or "functions" that are exported by this component. Every Meedio plugin, regardless of programming language used must have the 4 functions: OnMessage, EditCustomProperty, GetProperty and SetProperties.

In the script element, we tell Windows Scripting that we will be using VBScript as the language for this component. It is possible to use other languages, including JavaScript, Python or even Perl, but that is beyond the scope of this tutorial and we will be using VBScript for the sake of simplicity.

That strange CDATA thing is there to allow us to write the code freely without having to worry about special characters in XML, it is highly recommended. Remember that even though this is a Meedio plugin, it is also a Windows Script Component and, as such, an XML document.

Finally, inside the script element, we write the basic code for the 4 required functions. For each one, we list the parameters and return the appropriate result.

We save the resulting file as

<meedio installation dir>\plugins\module\TicTacToe\TicTacToe.wsc

which is what we specified in the Plugin Editor for the main file in the previous section.

The biggest problem with Windows Script Components is that it is not easy to check if we have made any typos in the file. The simplest way to do this is to register the component. To register it, use Windows Explorer and go to the folder where the file is saved. Once there right click on the file and choose Register. Try this now with our component.

If there are no problems with the file, you will see the message above.

If there is a mistake in the file, you will see a message similar to one shown above. The important thing to notice here is that the numbers in between square brackets are the line and column where the error is located; in this case, line 34, column 14. If you see this, you will need to go back to the file and look for any syntax errors at that location and then try to register again.

Once our component is free of mistakes, we are ready to do the first Meedio test; to ensure that the plugin can be found and loaded. This can be easily accomplished using another tool provided by Meedio called PluginTester.exe. It is located in the Meedio installation folder. Simply double click on it to execute it:

The Plugin Tester simulates what Meedio itself would do when it is looking for plugins. It scans the plugins directory and reads all the .plugin files it finds there. It performs some checks to make sure the contents of the .plugin files are valid and then shows you a list of all the plugins that it has found. The bottom part of the tool shows some interesting "behind the scenes" information that can come in handy when you are troubleshooting problems with your plugins.

If everything is in tip-top shape up to this point, the Plugin Tester should be listing our Tic Tac Toe plugin with the correct plugin ID as shown above. If the plugin is not listed, we can usually blame problems in the .plugin file. First, check the log messages shown by the Plugin Tester to look for any validation problems. If there are none, verify that the TicTacToe.plugin file is saved in the correct location and then run the Plugin Tester again.

If the plugin is listed, we can simply double click on the plugin's name to try and load it. In this case, the Plugin Tester is doing the same thing that Meedio or the Configuration application would do when trying to load a plugin; if it works here, it will work there.

Assuming that everything went well, the Plugin Tester should look something like the picture above. The Plugin Tester has loaded the plugin, retrieved its properties and displayed the list of properties. In our case, we have not yet specified any properties for the plugin, so the list says "This plug-in has no properties". But, we should be happy that everything is working as expected.

At this stage, we have a valid plugin that Meedio can find and load. It doesn't do anything yet, but we will get to that in the next section.

Creating the screen file

Now that we know the basics are in order, it is time to start thinking about what our plugin will actually do.

Our Tic Tac Toe plugin will be very simple; it will just present the user with a screen where he/she can play Tic Tac Toe against the computer. The user will be able to exit, play or start a new game.

Hey! We just wrote a Use Case for our plugin: we defined what it will do. Now, we can set out to make it happen.

The first thing we said is that it will "present the user with a screen". This is a basic requirement and Meedio provides a way for us to accomplish it, so we need to start thinking about creating this "screen".

Meedio has a built-in language for creating screens that is based on XML and is also similar to HTML. In short, it allows us to divide the screen into areas and place widgets or controls into these areas. Once the screen is defined in what meedio appropriately calls a screen file, our plugin code can create the screen inside Meedio and manipulate these widgets.

So, where do we start? We can start with Notepad and type the whole screen from scratch or we can base ours on the .screen files of existing plugins. Alternatively we could use the Meedio Theme Designer to create the screen visually. In our case, we will do it from scratch so that you can see the whole process and we can discuss the various steps.

When you are ready, run Notepad again and type in the following (or copy and paste it):

<screen template="main" first_focus="the-toolbar">
 
  <actions>

 
    <action name="close" command="back">
      <state name="close" caption="Close" standard="module.close"/>

    </action>
 
    <action name="new-game" command="play">
      <state name="new-game" caption="New game"/>

    </action>	
 
  </actions>
 
  <action_list name="menu-actions" actions="close,new-game" />

 
 
  <placeholder dest="CONTENT" >
 
    <cells>
      <cell>

      </cell>
    </cells>
 
  </placeholder>
 
</screen>

Save this file as

<meedio installation dir>\plugins\module\TicTacToe\TicTacToe.screen

This is a simple screen that has no real contents, but already includes some of the features we described in our Tic Tac Toe Use Case.

In the screen element, which is always the first one in a screen file, we specified that it should use the "main" template. The "main" template is one that is provided by most Meedio themes; it is a special kind of screen that has holes for us to include our own widgets. The idea behind using a template is that it makes it easier to create a bunch of screens that have a consistent look. The first_focus attribute tells Meedio which widget to focus when the screen is first shown. In our case, we have set it to "the-toolbar", which is the name of a widget provided by the main template. In the default theme, "the-toolbar" refers to the menu you see on the left hand side of almost every screen.

Actions

Next, we have an actions element that includes two action sub-elements. Simply put, actions are the basic things that the user will be able to do. In our Use Case, we said that the user will be able to "play, exit or start a new game". Aside from being able to "play", this translates well into the actions we have listed in the screen file.

Every action has a name, which is an arbitrary way to refer to the action internally. The user of our plugin never sees this name. In addition to this, an action can have a command that triggers it. Commands are all the things listed in the "Input" tab of the configuration application; they are names that are mapped to keys or remote control buttons. In the default configuration, the BACK command is mapped to the backspace key, for example. By listing the names of these in the command attribute of an action, we are saying that the action will be executed when the user invokes the command (by pressing a key or a remote control button, for example). So, we have assigned the BACK command to the action that will close our Tic Tac Toe module and the PLAY command to the action that will start a new game; pretty logical so far.

Inside each action are one or more state elements. States help us further define what the action will do and how it will be displayed. In some cases, a single action can have multiple states, such as "Shuffle On" and "Shuffle Off", but more often than not, each action has a single state. The state, again, has an arbitrary name. This name can be the same name as the action name. What follows the name of the state can vary greatly, but it is very common to include a caption for the state. This caption is what the user will see and will usually be translated if the user is using a different language file. So, we gave our two states some obvious captions.

In the case of our close state, we added a strange "standard" attribute. This is a simple shortcut that means our plugin will have to do less work. There are a number of "standard" things a state can do and one of them is to close the current module. We have specified the standard state "module.close". It just means that when this action executes, Meedio will close the module, effectively exiting our Tic Tac Toe plugin. There is no standard state for a new Tic Tac Toe game, so we will need to implement that one ourseleves inside the plugin code.

Next in line is an action-list element. This element lets us create a named, ordered list of the actions we have specified in the screen file. It just so happens that the main template we are using takes the action list called menu-actions and automatically places them in the left hand menu. It all serves to create less work for us.

An action list has a name and a comma-separated list of action names to include in the list. Typically, widgets that display action lists, display them in the same order they are listed here; which means that the left hand menu will have a "button" with the caption "Close" and another with the caption "New game" below the first. This is pretty much what we want.

Let's ignore the rest of the screen file and test the screen.

Testing the screen

Once the skeleton for the screen file has been saved, we can actually test it to make sure it is working properly. It won't be a very exciting test because our screen does not yet have any real content, but we can at least see that it works. It also serves to show you another tool we provide (and use ourselves) to make things easier.

To test the screen file, run the Meedio Configuration Application which is also located in the installation directory.

  • Go to the Menu tab and select the first group module, which is usually the second one called "Meedio" if you have a standard installation.
  • Click the Add button and select the Screen Tester Module from the list of possible modules. Do not select Tic Tac Toe yet.
  • Select the Screen Tester Module you just added and then go to the Module Properties tab on the right hand side.
  • For the Screen property, select the TicTacToe.screen file we saved earlier.

The settings should look like the picture above. Now, click the Launch button.

After Meedio starts, go to the Screen Tester Module we created and select it. If you are using the default theme, you will see a screen similar to the picture above. Coincidentally, it is recommended that you use the default theme when you are developing screens to ensure that they run well in a default configuration.

In the screen we see our two actions manifested in the left hand menu. We also see that pressing the Close button actually closes the module. The right hand side of the screen is painfully empty, but we'll get to that next.

When you are creating screens, it is always a good idea to use the screen tester module to see how they will look.

Creating some resources

Before we continue on with the screen, we are going to create a couple of things that we'll need later on. If we're going to play Tic Tac Toe, we will need some images to represent the X's and O's. You can use your favorite tool to do this, and Meedio works with a variety of image formats, but we will be using PNG's because they offer a transparent layer.

Because I have no artistic talent whatsoever, I decided to use two shapes that my photo editor has in its clip art library for the X's and O's. I saved these in a new directory called images under the plugin's directory. I used the file names ttt-o.png and ttt-x.png for them. The "ttt" stands for Tic Tac Toe. I made the images square at 175 x 175 pixels, which means they should scale well. Although Meedio will scale the images automatically, we need to make sure they are not so small that they will look awful at higher resolutions.

Now, we need a way to refer to these images. Remember that when your plugin is installed on another user's computer, you won't know where it has been installed and therefore you will not be able to refer to them by using file names. Meedio provides this ability in what it calls resource files.

Resource files are, again, XML files that allow you to assign names and properties to resources that will be used in screen files, such as images, colors, fonts and various other things. The format of a resource file is very simple and the files have the .resources extension.

Fire up Notepad again and enter this into it:

<resources>
 
  <images>
 
    <ttt-x-image source = "images\ttt-x.png" />

  
    <ttt-o-image source = "images\ttt-o.png" />
 
  </images>
 
</resources>

Save this file as

<meedio installation dir>\plugins\module\TicTacToe\TicTacToe.resources

This file is fairly simple, it always begins with the resources element. Inside, there can be a variety of other elements that define different reource types, one of which is images. Inside the images element, we have created two images. Here, the name of the element, such as "ttt-x-image" is the name we will use to refer to the image from within our screen file and our plugin code. The source attribute tells Meedio where the actual file is, relative to the location of the resource file. This solves the problem of not knowing where the plugin is installed, because wherever it is installed, our images will be in a folder called "images" which will always be located where the resource file is.

Now that we have our images, we are ready to proceed.

Creating the Tic Tac Toe board

We are ready to go back to our screen file and add the playing area. But, before we do that, we will make one additional change to it to include the resource file we created in the previous step.

<screen template="main" first_focus="the-toolbar" resources="TicTacToe">

We simply edit the screen element of the screen file and include a reference to the resources file as shown above. We just add the resources attribute and the name of the resource file; we don't need the path to it or the extension as Meedio will make the correct assumptions about them.

  <placeholder dest="CONTENT" >

 
    <cells>
      <cell>
      </cell>
    </cells>
 
  </placeholder>

When we first talked about the screen file, we mentioned that it is using a template file which provides "holes" for us to put our widgets. In the snippet above, you see the placeholder element. This element is used to tell Meedio to put whatever is inside it into the "hole", or "place holder" called "CONTENT". The main template we are using defines a place holder with the name "CONTENT" which is the right hand side of the screen. This allows us to create screens that don't have much position information; they simply put their content into the areas defined by the template. So far, this area has been empty, but that is where our playing area will be.

The playing area is nothing more than a 3x3 grid where the X's and O's will go. Fortunately, Meedio includes a widget that can approximate this concept very closely. The menu widget does basically that. The only problem is that the menu widget also does a lot of other things, so we have to tweak it to do exactly what we want.

So, we will modify our screen file as follows:

  <placeholder dest="CONTENT" >

 
    <cells>
      <cell>
 
        <menu name="board">
          <mode name="default" preset="simple-thumbnail-mode"

 
                col_count    = "3"
                col_space    = "10"
                row_size     = "1/3"
                row_space    = "10"

                scroll_size  = "0"
                image_format = "fit-img-format"
          >
          </mode>
 
          <item image="ttt-x-image" />

          <item image="ttt-o-image" />
          <item image="ttt-x-image" />

          <item image="ttt-o-image" />
          <item image="ttt-x-image" />

          <item image="ttt-o-image" />
          <item image="ttt-o-image" />

          <item image="ttt-o-image" />
          <item image="ttt-x-image" />

 
        </menu>
	
      </cell>
    </cells>
 
  </placeholder>

Above, I am only showing the relevant snippet of the screen file; you will be able to see the whole file later on. If you want, you can save the file again and run the screen tester module again; you will see that things are starting to take shape (aside from my horrible choice of images).

If you do, you will see that our screen looks something like the picture above. The "tic tac toe" title is not magic, I went in and edited the caption for the Screen Tester Module to make it look a bit more like the real thing.

But wait!!! It looks like someone has already played a game and we haven't written a single line of code yet. This is a little trick I used in the screen file above to see what it would look like. It corresponds to the 9 item elements I added.

Before we get too far ahead of ourselves, let's look at the new things in the screen file.

Inside the placeholder element, there is a cells element and a cell element inside that. These serve to divide the screen area into manageable pieces that can contain widgets. For more information about this, see Screen Files: Layout. In our case, we are going to use the whole area on the right hand side for the board, so we don't need to create cells. However, Meedio dictates that all widgets must be inside a cell element, and all cell elements must be inside a cells element, so we create one of each to satisfy this requirement.

Inside the cell, we have placed a menu widget. The menu widget is the most common of them all, as it can serve a lot of different purposes. Meedio does not have the concept of single buttons; since buttons are typically arranged in groups, Meedio uses menus to create groups of buttons. Menus are also used to display lists of things and grids with thumbnails. The Menu widget is very powerful.

To begin, we gave the menu widget the name "board". This will allow our plugin code to reference the menu and manipulate it at run-time. Only controls that you want to use from within your code need to have a name, and their names must be unique in the entire screen file (and any templates referenced by the screen).

Typically, widgets include all of their properties within their main element, but the menu is a bit different. The menu widget includes all of its properties within a mode element. Each mode has a name of its own. This allows a single menu control to take on different "shapes". For example, one mode could be a thumbnail display and another could be a list display. They both contain the same data, but they display it differently. By pre-configuring modes, the plugin can easily switch between them at run-time in response to the user. In our case, we will only be using a single 3 x 3 mode, so we created a default mode.

Since each mode in a menu control can have a large number of properties, Meedio provides a number of preset modes in the theme's resource file. So, when we create a new mode for our menu widgets, we can base it on a preset mode and only change, or override a few properties. In our case, you see that we have used the "simple-thumbnail-mode" preset. You can find that preset in the file default.resources of the default theme.

Following the preset, we begin to set properties specific to our menu.

          <mode name="default" preset="simple-thumbnail-mode"

 
                col_count    = "3"
                col_space    = "10"
                row_size     = "1/3"
                row_space    = "10"

                scroll_size  = "0"
                image_format = "fit-img-format"
          >
          </mode>

We begin with col_count which sets the number of columns displayed to "3". Then, we use col_space to define a 10 pixel space between the columns. Next, we use a fraction to define the size of each row in the menu with row_size. Menu widgets have a fixed number of columns, so they cannot scroll to the right, but they can have any number of rows. So, we use "1/3" to tell the widget that each row should be 1/3 of the total height of the widget. In effect, this means that our menu will only show 3 rows at a time; if it had more than that, the user would have to scroll to see more rows. Then, we use row_space to define a 10 pixel space between each row, just like we did for columns. Since we know that our menu will have only 3 rows, we set scroll_size to 0, which serves to hide any scroll bars or arrows. Finally, we set the image_format that will be used to display images in this menu. "fit-img-format" is the name of an image format resource that is already defined in the default resource file for the theme; it basically says that images will fit their bounding box, retain their original aspect ratio, can be enlarged and will be aligned to the center both vertically and horizontally.

          <item image="ttt-x-image" />
          <item image="ttt-o-image" />

          <item image="ttt-x-image" />
          <item image="ttt-o-image" />

          <item image="ttt-x-image" />
          <item image="ttt-o-image" />

          <item image="ttt-o-image" />
          <item image="ttt-o-image" />

          <item image="ttt-x-image" />

After the mode element, we created 9 test "items" for the menu. Every menu widget holds any number of items. The items are displayed from left to right and top to bottom according to the number of columns in the menu. Each item contains an arbitrary list of names and values. In technical terms, an item is an Associative Array. In this case, each item will contain the name "image", and for each item, the value of "image" will be what we specified in the screen file. In the previous section we create a resource file to give the images names; those are the names that we using here, so that we don't have know where the actual files are. So, "ttt-x-image" is the name of an image resource that is located in the file "images\ttt-x.png".

Even though each item can have any number of names and values, there are a couple that are "magical" and are treated in a different way by the menu widget. These are mainly "image" and "caption". By default, the menu widget will display the image referenced by each item's "image" value and the text contained in the "caption" value. Of course, this can be changed, and there are ways to configure a menu widget to display several images and captions for each item, but that is beyond the scope of this tutorial. All we need is an image in each item. When we start writing the plugin code, you will see that we will use the "image" value to see if a cell is occupied and by what player it is occupied.

In reality, we will remove the item elements from the screen file and add them dynamically at run time.

Writing the code

Now, we are finally ready to work on the actual code for the plugin. In this section, I will only show relevant snippets of the wsc file instead of the entire file every time.

Properties

Let's begin by talking about the 4 functions that each plugin must implement. Of the 4, 3 have to do with properties. Properties are the means by which a user configures your plugin. Meedio provides a standard user interface that allows users to configure any plugin. In cases where the standard interface is not enough, you can use custom properties and your plugin can create custom property pages for them.

The first thing that Meedio (or the configuration application) does is to load your plugin and ask it to list its properties. It does this by calling the GetProperty function repeatedly until it returns False. Each time the function is called, it is pased a new index, so you know where you are; the first one is 1. It is important to note that you must return False eventually, or Meedio will just keep calling GetProperty and get into an infinite loop. Every time that GetProperty is called, Meedio passes you an new object called IMeedioPluginProperty, which you use to describe each property to Meedio. In our case, we don't really need any properties, but we will create one just to demonstrate the concept. We will use a property to allow the user to choose whether he/she plays using the X's or O's.

function GetProperty( Index , Prop )
 
  if Index = 1 then
 
    Prop.Name = "x-or-o"

    Prop.Caption = "Do you want to play with X's or O's?"
    Prop.HelpText = "Choose whether you want to use X's or O's."
    Prop.DataType = "string"

    Prop.DefaultValue = "x"
    Prop.Choices2( "x" ) = "X's"

    Prop.Choices2( "o" ) = "O's"
 
    GetProperty = vbTrue
 
  else

 
    GetProperty = vbFalse
 
  end if
 
end function

So, you see that we have changed the GetProperty function. If the index is 1, it means we are on our first property, so we set all the required values. We start by giving the property a name. This is an internal name which we will use to identify the property value later on, the user will never see this. Then, we set the caption and help text which the user will see in the configuration application. We set the property's data type to "string" and the default value to "x". Then, we use another IMeedioItem to create a list of possible choices for the property values. In the configuration application, the user will be shown a combo box to pick one of the choices. For each choice, we set an ID, which the user will not see and a value, which will represent the text the user will see for the choice. Finally, we return true to tell Meedio that we specified a property. If the index is anything other than 1, we return false to let Meedio know that we are done.

At this stage, you can run your plugin with the Plugin Tester or even inside Meedio to see that our property is available and it can be configured.

The next thing that Meedio will do is to tell us the values that the user has specified for our properties. It does this via the SetProperties function. SetProperties has two arguments, the first is an IMeedioItem that contains the names of all the properties we specified in the GetProperty function and their corresponding values as set by the user. This function is called only one, since Properties contains all the values. SetProperties should return true unless there was a problem setting the property values. If there was a problem, you can populate the ErrorText parameter with an error message that will be shown to the user and return false. This allows you to validate the property values.

Dim UserImage
 
function SetProperties( Properties , ErrorText )
 
  UserImage = Properties( "x-or-o" )

 
  SetProperties = vbTrue
 
end function

First of all, we create a global variable called "UserImage" to store the property value. Then, in the SetProperties function, we simply set that variable to the value of the property called "x-or-o". This is the name we gave it in the GetProperty function. So, in the end, UserImage will contain either the string "x" or "o", which are the possible values we specified for this property in GetProperty. We simply save that value; we will put it to use later.

As we mentioned earlier, you can create custom property pages by using the "custom" property data type. If you do, Meedio will use the EditCustomProperty function to let you display a dialog to edit the property. In our case, we don't have any custom properties, so this function just returns true.

Messages

So, now your plugin knows all of its property values and it is ready to run. What happens next is that Meedio loads your plugin and begins to send it messages. The time at which your plugin is loaded depends on what type of plugin it is. General and input plugins are loaded when Meedio starts, module plugins are only loaded when the user invokes them, usually by selecting them from a menu. Regardless of when it is loaded, each plugin receives a unique message as the very first one.

Let's talk a bit about messages. Messages are pieces of data that Meedio uses to communicate between itself and all the loaded plugins. Plugins can also send messages to each other. Messages can notify plugins of events happening or can ask plugins to perform certain actions. When a plugin creates a screen, it also receives messages from the controls inside that screen.

Every message contains a subject, which is a string describing the purpose of the message. Subjects are usually all lower case and contain multiple parts separated by periods. There is a document describing Message Subject Guidelines. There are a number of standard message subjects and others that are specific to certain plugins. While we don't have an exhaustive list documented, you can find out about some of them in System Messages. In a lot of cases, plugins have to let Meedio know which message subjects they want to receive. In other cases, messages are automatically delivered to plugins because Meedio knows that they want to receive them. For example, messages sent by controls on a screen are automatically sent to the plugin that created the screen. Messages sent by the system (Meedio itself) are delivered automatically to all plugins.

The IMeedioMessage object contains several functions that let you identify the subject of the message. While you can always read the value of its subject property, these functions make it easier to do some checks. For example, the basic function SubjectIs lets you compare the subject of a message to an arbitrary string and even lets you include simple regular expressions. So you can do:

  Message.SubjectIs( "music.*" )

To check that the subject matches "msuic.*".

In addition to the subject a message contains additional information. Every plugin loaded has a handle (a unique number), and every message contains the handle of the plugin that sent it. You can check the documentation for IMeedioMessage for all of its properties. A message is also an IMeedioItem. That means that it can carry as its payload any number of name/value pairs. This is what is used to send parameters along with messages. The names used are arbitrary and certain plugins expect certain named values in specific messages. For example, the music player plugin accepts messages with the subject music.play-file and the message must contain a key named "file" with the path to the file to play. Messages can also contain a list of items; for cases when a lot of information must be passed via a message.

While your plugin is running, it simply receives messages. It can do all of its processing based on these messages. This is called event driven programming, because each message can be thought of as an event and everything that is done is in response to these events.

Now that we know a little about messages, we can go back to that unique message we said Meedio will send our plugin as soon as it is loaded. This message has the subject system.plugin-loaded and it is guaranteed to be the first message any plugin receives. It is also guaranteed that it will only be received once by each plugin instance. Fortunately, IMeedioMessage provides a utility function to check for this subject, which is called IsPluginLoaded. This message is very important because it signals to our plugin that it needs to set itself up and start running. So, most plugins will perform their initialization in response to this message.

Dim MyScreen
Dim TheBoard
Dim GameOver
Dim ComputerImage
 
function OnMessage( Sys , Msg )

 
  OnMessage = vbTrue
 
  if Msg.IsPluginLoaded then
 
    set MyScreen = Sys.NewScreen( "TicTacToe" , Nothing )

 
    set TheBoard = MyScreen.Controls( "board" )
 
    TheBoard.Clear
 
    for I = 1 to 9

      TheBoard.Add
    next
 
    GameOver = False
 
    if UserImage = "x" then

      UserImage     = "ttt-x-image"
      ComputerImage = "ttt-o-image"
    else
      UserImage     = "ttt-o-image"
      ComputerImage = "ttt-x-image"

    end if
 
    MyScreen.Show
 
  end if
 

end function

So, let's look at our first bit of code in the OnMessage function. First, we create a couple of global variables to hold references to the screen and the board; more on these later. Then, we check for the system.plugin-loaded message we discussed above. In response to that message, we will initialize our plugin.

In case you haven't noticed, the OnMessage function gets two parameters; one being the message and another being the Meedio System Object. This object is the gateway to all the functions Meedio provides to our plugin. It is fairly well documented in IMeedioSystem. This object is used to create messages, screens and get other vital bits of information from Meedio.

    set MyScreen = Sys.NewScreen( "TicTacToe" , Nothing )

The first thing we do with the system object is to create our screen. We only need to pass the name of the screen file with no extension or path because Meedio will figure all of that out automatically. The second parameter to the NewScreen function is not used yet, so we pass Nothing. This call tells Meedio to load our screen file and give us an IMeedioScreen object that we can use to manipulate the screen at run time. This is a fairly common thing in Meedio; it creates objects we can use to manipulate things. We should really be doing some error checking, because the returned screen could be null if Meedio is unable to create it, but we will skip that for the sake of brevity.

    set TheBoard = MyScreen.Controls( "board" )

Next, we use the Controls property of the screen object to get an object that will represent the menu widget we placed in our screen file. If you remember, we named it "board" in the screen file, and this is the name we use to find it here. Although the Controls property is documented as returning an IMeedioControl object, this object will also have the interface of the specific widget retrieved, which in this case is IMeedioMenu. Look at the documentation for IMeedioMenu and you will see all the different properties and functions it has. Note that the TheBoard object will be valid as long as our plugin is running, so we can get a reference to it once and then start using it.

    TheBoard.Clear
 
    for I = 1 to 9

      TheBoard.Add
    next

Now, we use the methods and properties of IMeedioMenu to clear all of the test items we added to it in the screen file and then add 9 new items to it. This is not necessary, but it is a good idea in this case so that we have full control of the contents of the board. The 9 items are empty - basically a clear board with no images in it.

    GameOver = False

 
    if UserImage = "x" then
      UserImage     = "ttt-x-image"
      ComputerImage = "ttt-o-image"

    else
      UserImage     = "ttt-o-image"
      ComputerImage = "ttt-x-image"
    end if

Then, we set-up some variables we will use later. We will need a way to know if a game is over, so we have a global GameOver variable which we initially set to false. At this stage, the UserImage variable contains either "x" or "o" which is the value the user configured. To make things easier for us, we change it to contain the full name of the appropriate image resource. And, we set the ComputerImage to the other value.

    MyScreen.Show

Finally, we tell the screen to show itself. From this point on, we will respond to messages sent by the widgets on the screen - which will come when the user interacts with them.

At this stage our plugin is in working order. We no longer have to use the Screen Tester Module and can, instead, add the plugin to our Meedio menu using the configuration application. Coincidentally, the Screen Tester Module is a plugin that has pretty much this same code in it; the only difference is that it takes the name of the screen file as a property.

Now, we need to code the logic of the Tic Tac Toe game.

Coding the game

Our plugin is running, everything has been initialized, the screen is showing and we are now ready for the user to do something. Well, there are only a few things the user can do. For one, he could click on the Close action, but that is handled automatically by Meedio. He could also click on the New game action. Finally, he can click on the board to start actually playing. Let's handle the New game action first because it is the easiest.

  if Msg.IsPluginLoaded then
 
    ...
 
  elseif Msg.IsFromScreen( MyScreen ) then

 
    if Msg.IsAction and ( Msg( "action" ) = "new-game" ) then

 
      Sys.SpyLog( "New game!" )
 
      TheBoard.Clear
 
      for I = 1 to 9

        TheBoard.Add
      next
 
      GameOver = False
 
    end if

 
  end if

I omitted the previous code because it has not changed, but now we have added another check for messages. The call to the function IsFromScreen( MyScreen ) will only return true if the screen passed in is valid and the message was sent by that screen. This prevents us from processing erroneous messages and lets us narrow down the source of a message.

One of the messages that the screen can send us is an action message, which tells us when the user has clicked on an action. The action message will contain the name of the action and the name of that action's current state. Since we have a single action which we need to handle, we check for its name.

      Sys.SpyLog( "New game!" )

Then, we issue this strange SpyLog call. This is a means to help debug your plugin and make sure that it is doing what you expect it to. This call sends the text passed in to the spy log, which is a window opened by Meedio if you run it with the -debug parameter. The spy log shows you all the messages that Meedio is processing and any debug statements the plugins are emitting. When you close Meedio, the contents of this log are saved as Meedio.debug.log which can be a valuable aid in debugging problems.

The rest of our response to the "new-game" action is fairly standard; we clear the board again and set the GameOver variable to False. We should have placed this code in a separate function, since we do the same thing when we first initialize the plugin, but we'll leave those optimizations for later.

So, that leaves the user clicking on the playing area. When this happens, our board control will send us a command message with the SELECT command.

    if Msg.IsAction and ( Msg( "action" ) = "new-game" ) then

      
      ...
 
    elseif Msg.IsFromControl( TheBoard ) and Msg.IsCommand( "SELECT" ) then

 
      Sys.SpyLog( "The user clicked on the board!" )
 
      if GameOver then
        exit function

      end if
 
      Set Item = TheBoard.Selected
 
      if Item( "image" ) <> "" then

        exit function
      end if
 
      Item( "image" ) = UserImage

 
    end if

To detected the user clicking on a square, we use the IsFromControl and IsCommand functions. The first one verifies that the message comes from the control we passed in (our playing board) and the second one verifies that it is a command, more specifically the SELECT command.

We log a debug message, then we check to see if the game is over. If so, we exit without further ado.

      Set Item = TheBoard.Selected

This call, lets us find out which item the user clicked on. It returns the currently selected IMeedioItem in the menu. We don't really care to identify the item, we just need to know what it contains. So, if the item already contains an image, we exit. Otherwise, we set the item's image to the UserImage. This will take care of drawing the right image in the right place and the results are immediate. You can run the plugin again and you will now see that clicking on the playing area will add either an X or an O depending on how we configured the plugin. Now, we need to move on to the computer's turn and detecting whether the game is over.

Dim MyScreen

Dim TheBoard
Dim GameOver
Dim ComputerImage
 
Dim Lines(8)
 
Lines(0) = Array( 0 , 1 , 2 )

Lines(1) = Array( 3 , 4 , 5 )
Lines(2) = Array( 6 , 7 , 8 )

Lines(3) = Array( 0 , 3 , 6 )
Lines(4) = Array( 1 , 4 , 7 )

Lines(5) = Array( 2 , 5 , 8 )
Lines(6) = Array( 0 , 4 , 8 )

Lines(7) = Array( 2 , 4 , 6 )
 
function IsThereAWinner( Sys )

 
  IsThereAWinner = vbFalse
 
  for I = 0 to 7
 
    Image1 = TheBoard.Items( Lines( I )( 0 ) ).Values( "image" )

    Image2 = TheBoard.Items( Lines( I )( 1 ) ).Values( "image" )

    Image3 = TheBoard.Items( Lines( I )( 2 ) ).Values( "image" )

 
    if ( Image1 = Image2 ) and ( Image2 = Image3 ) then
 
      if Image1 <> "" then

 
        IsThereAWinner = vbTrue
 
        if Image1 = ComputerImage then
          MyScreen.Data( "subtitle" ) = Sys.Translate( "I win" )

        else
          MyScreen.Data( "subtitle" ) = Sys.Translate( "You win" )
        end if

 
        exit function
      end if
 
    end if

 
  next
 
end function
 
function ComputerPlay( Sys )
 

  if IsThereAWinner( Sys ) then
 
    ComputerPlay = vbTrue
 
  else
 

    ComputerPlay = vbFalse
 
    Dim UserCount
    Dim ComputerCount
    Dim Moves( 8 )

 
    for I = 0 to 8
      Moves( I ) = 1

    next
 
    for I = 0 to 7
 
      UserCount = 0

      ComputerCount = 0
      EmptyCount = 0
 
      for J = 0 to 2

 
        Image = TheBoard.Items( Lines( I )( J ) ).Values( "image" )

 
        if Image = UserImage then
 
          UserCount = UserCount + 1
          Moves( Lines( I )( J ) ) = 0

 
        elseif Image = ComputerImage then
 
          ComputerCount = ComputerCount + 1
          Moves( Lines( I )( J ) ) = 0

 
        else
 
          EmptyCount = EmptyCount + 1
 
        end if
 
      next

 
      Move = 0
 
      if EmptyCount > 0 then
 
        if ComputerCount = 2 then

 
          ' winning move
          Move = 3
 
        elseif UserCount = 2 then

 
          ' blocking move
          Move = 2
 
        end if
 
        if Move > 1 then

          for J = 0 to 2
 
            if ( Move > Moves( Lines( I )( J ) ) ) 
		and ( Moves( Lines( I )( J ) ) <> 0 ) then

 
            if Move = 3 then
              TheBoard.Items( Lines( I )( J ) ).Values( "image" )
		= ComputerImage
              ComputerPlay = vbTrue
              MyScreen.Data( "subtitle" ) = Sys.Translate( "I win" )

              exit function
             end if
 
              Moves( Lines( I )( J ) ) = Move
            end if

 
          next
        end if
 
      end if
 
    next

 
    Sys.SpyLog( " " & Moves( 0 ) & Moves( 1 ) & Moves( 2 ) )

    Sys.SpyLog( " " & Moves( 3 ) & Moves( 4 ) & Moves( 5 ) )

    Sys.SpyLog( " " & Moves( 6 ) & Moves( 7 ) & Moves( 8 ) )

 
    for I = 0 to 8
      if Moves( I ) = 2 then

        TheBoard.Items( I ).Values( "image" ) = ComputerImage
        exit function
      end if

    next
 
    EmptyCount = 0
 
    for I = 0 to 8

      EmptyCount = EmptyCount + Moves( I )
      if Moves( I ) = 1 then

        Location = I
      end if
    next
 
    if EmptyCount = 0 then

      MyScreen.Data( "subtitle" ) = Sys.Translate( "Tie" )
      ComputerPlay = vbTrue
      exit function

    end if
 
    if EmptyCount > 1 then
      Location = 4

    end if
 
    Do
 
      if Moves( Location ) = 1 then

        TheBoard.Items( Location ).Values( "image" ) = ComputerImage
        exit do
      end if

 
      Location = Int( ( 8 + 1 ) * Rnd )
 

    Loop
 
    if EmptyCount = 1 then
      MyScreen.Data( "subtitle" ) = Sys.Translate( "Tie" )

      ComputerPlay = vbTrue
    end if
 
  end if
 
end function

 
'...............................................................
 
function OnMessage( Sys , Msg )
 
  OnMessage = vbTrue
 
  if Msg.IsPluginLoaded then

 
    set MyScreen = Sys.NewScreen( "TicTacToe" , Nothing )
 
    set TheBoard = MyScreen.Controls( "board" )

 
    TheBoard.Clear
 
    for I = 1 to 9
      TheBoard.Add

    next
 
    GameOver = False
 
    if UserImage = "x" then

      UserImage     = "ttt-x-image"
      ComputerImage = "ttt-o-image"
    else
      UserImage     = "ttt-o-image"
      ComputerImage = "ttt-x-image"

    end if
 
    MyScreen.Show
 
  elseif Msg.IsFromScreen( MyScreen ) then

 
    if Msg.IsAction and ( Msg( "action" ) = "new-game" ) then

 
      Sys.SpyLog( "New game!" )
 
      TheBoard.Clear
 
      for I = 1 to 9

        TheBoard.Add
      next
 
      MyScreen.Data( "subtitle" ) = ""

 
      GameOver = False
 
    elseif Msg.IsFromControl( TheBoard ) and Msg.IsCommand( "SELECT" ) then

 
      Sys.SpyLog( "The user clicked on the board!" )
 
      if GameOver then
        exit function

      end if
 
      Set Item = TheBoard.Selected
 
      if Item( "image" ) <> "" then

        exit function
      end if
 
      Item( "image" ) = UserImage

 
      GameOver = ComputerPlay( Sys )
 
    end if
 
  end if

 
end function

Above is the finished code. I'm not going to go into the details of the algorithms used to determine if there is a winner or how the computer figures out how play. But, there are a few things to note here. For one, we pass the IMeedioSystem object to other functions so that they can use it; this is perfectly normal and recommended.

          MyScreen.Data( "subtitle" ) = Sys.Translate( "You win" )

It is also worth explaining this line a little bit. In essence, we are using the subtitle of the screen to show the results of the game. Basically, the screen's template defines an area for the subtitle to go and calls it "subtitle". Every screen has an associated IMeedioItem that can hold data items that are then displayed on the screen. By placing values into those data items, other widgets will read the values and show them. This saves us having to know the name of the label that holds the subtitle, and if there is no such label, nothing will go wrong. It allows theme developers to move things around or remove them altogether without causing too much trouble for plugins. The second part uses the Translate function of the system object, which returns a translated copy of the text we passed in. This makes it easy to make sure that our strings can be translated.

So, we have finished our plugin, and it works very well. It could be a little bit flashier, but it does the job. Not bad for a few XML files. In the next step, we are going to publish the finished plugin to MAID, and that is also where you can download the whole thing.

Packaging the plugin for MAID

Finally, we are ready to publish our plugin so that the rest of the worl can use it. This could not be easier.

First, go to the directory where your plugin is installed and double click on the .plugin file. This will open up the Meedio Plugin Editor that we used in the first section of this tutorial. If you want to make changes to the information here, feel free to do so, otherwise, you can simply click the Package plugin button.

When that is done, the plugin editor will create a file called TicTacToe.mpp which contains all of our plugin's files. These .mpp (Meedio Plugin Package) files are nothing more than zip files with a different extension; they can be automatically installed by Meedio. Note that the plugin editor will create the file in the same directory you have the plugin installed and if want to test installing it, you will need to move it somewhere else first.

Now that we have the plugin package ready, we can go to MAID and submit it. Note that you must first have an account on our forum to do this; you can easily register for one.

So, we go to http://meedio.com/maid and log-in with our account

At the bottom left hand side of the page is a box that lets us manage our plugins. We click on Submit a new item and we are prompted for the location of the .mpp file. We enter it and click on Submit.

MAID then reads our mpp file and loads all of its information; it then presents us with a form where we can edit some of the information and possibly enter additional information. We do so and then click on Submit.

That's it, we're done. You can see the actual plugin in MAID.

I hope you enjoyed this in-depth tutorial and that you can see how easy it is to create powerful plugins for Meedio even if you don't have a compiler.