Thursday, February 1, 2007

MCMLPad, and a Better Blog

Three quick notes for todays post.

1) MCMLPad (the program used to test your MCML interfaces) does NOT scale correctly. I'm sure you'll find a reason for this in the Microsoft Knowledgebase, filed somewhere under 'flimsy justifications', but in the mean time be aware that if you are testing something to ensure it size and layout is correct, launch MCMLPad from Media Center instead

When started from Media Center, MCMLPad will function correctly and scale appropriately.

I blew almost two hours trying to figure out how to scale the darn interface properly with ScaleLayouts, and wondering why none of the MS examples included the basic functions to scale the interface - only to find out that it's an odd quirk with MCMLPad.

Thought I may save you guys the time :)

2) My next tutorial was going to be on what I called the 'CategoryBar', the blue bar that allows you to choose the category/sort order in most Media Center windows. However, someone beat me to it (and quite franky, is much better than I am anyway). Check out http://mobilewares.spaces.live.com/ to see a master at work! He also has an excellent tutorial in creating 'Gel Buttons', the new version (found in Now Playing) of the old Media Center 2005 style interface buttons.

3) I've opened a new SourceForge project, called MCMLookalike (www.sourceforge.net/mcmlookalike), to create open source, shared libraries for MCML development. Feel free to use them and contribute to the project - the first files should be uploaded this afternoon.

Wednesday, January 31, 2007

Tips & Tricks: 'Global' Variables

A quick word for the wise when it comes to MCML and your variables.

As much as you would like every UI to be it's own completely autonomous control, there are times when you need real feedback from your UI's.

This can actually be quite a problem, since a UI can not talk to it's parent.

So what is the trick? It's actually not too difficult, but for the newbie it can be very confusing.

We have already introduced properties, allowing you to set the attributes of the UI's you are creating. As well as properties, we have locals. These are in a very similar form to properties, with the only real difference being that you can't tell a UI what it's locals should be.

The trick is to take one of your local variables and basically just 'pass it on' as properties to all other objects that need access to it.

BUT - and here's the trick - you need to be aware of what TYPE of property you are using. This is because the variables work differently depending on what type you use.

If you use an object from the cor: namespace (such as cor:String, cor:Int32, cor:Boolean etc.) then you have created a simple type, like 'int' or 'long' in C. If you pass simple objects to a UI, it gets it's own new copy of the variable, meaning that if you change the value in any of your sub-items, the change will only effect THAT ITEM.

However, if you use something more complicated, a CLASS like EditableText for instance, every UI that is sent it as a property gets a reference to the object. This means that when you change a value in ANY of the UI's you have passed it to, it will be changed for ALL UI's.

<UI Name="MainUI">

  <Locals>
    <cor:String Name="Brand" cor:string="My Brand">
    <EditableText Name="Area" EditableText="None">
  </Locals>

  <Content>
    <Panel Layout="VerticalFlow">
      <Children>
        <Text Name="BrandName" Color="White" Font="Tahoma,20"/>
        <Text Name="AreaName" Color="White" Font="Tahoma,20"/>
        <me:BrandedOption BrandVar="[Brand]" AreaName="Option #1" BrandName="ACME" AreaVar="[Area]"/>
        <me:BrandedOption BrandVar="[Brand]" AreaName="Option #2" BrandName="Someone Else" AreaVar="[Area]"/>
      </Children>
    </Panel>
  </Content>

  <Rules>
    <Binding Source="Brand" Target="BrandName.Content">
    <Binding Source="Area" Target="AreaName.Content">
  </Rules>

</UI>

<UI Name="BrandedOption">

  <Properties>
    <cor:String Name="BrandVar" cor:string="$Required">
    <cor:String Name="BrandName" cor:string="$Required">
    <EditableText Name="AreaVar" EditableText="$Required">
    <cor:String Name="AreaName" cor:string="$Required">

  </Properties>

  <Content>
    <Panel Layout="HorizontalFlow">
      <Children>
        <Text Name="ButtonArea" Color="Red" Font="Arial,20" Content="[AreaName]"/>
        <Text Name="ButtonBrand" Color="Red" Font="Arial,20" Content="[BrandName]"/>
      </Children>
    </Panel>
  </Content>

  <Rules>
    <Condition Source="[Input.MouseFocus]" SourceValue="true">
      <Actions>
        <Set Target="[BrandVar]" Value="[BrandName]">
        <Set Target="[AreaVar]" Value="[AreaName]">
      </Actions>
    </Condition>
  </Rules>

</UI>


I haven't actually TESTED this UI (although I do something similar in my existing MCML) but that will give you the basic outline.

What we have is an interface that has two text boxes in white, giving you the current brand name setting, and the current area name setting. These are constantly updated with the rule we have specified, which makes sure the value of 'Area' and 'Brand' are copied into the text controls whenever the values are updated.

There are also two buttons. Each button has two text elements, the brand and the area/type of a product (set with the AreaName and BrandName properties) and the button is also passed our global Brand and Area variables through the AreaVal and BrandVal.

In the buttons, we have a rule that says that whenever the object is given mouse focus (Input.MouseFocus = true) then we are to set the AreaVal and BrandVal properties to AreaName and BrandName (the names displayed on the button).

What you should find when you do this is that when you roll over a button, the AREA will change, but the BRAND will not. This is because of the rules I explained earlier.

So now you know how to share a variable through your entire UI. This will come in handy in the next project discussed.

Tuesday, January 30, 2007

Looking Like Media Center: Background Text

OK, we now have the tools in hand to create our first UI element - the text that appears in the background of Media Center interfaces (check in the top right corner of almost any Media Center window).

It's a fairly simple beast really - we simply need a text control that gradually fades out vertically.

But we are going to implement this as a reusable control. So put your MCML hats on, and let's dive in.

<UI Name="BackgroundText">
</UI>


That's kind of obvious really - we have defined our control.

Like our previous example, we are going to need to be able to change the text that appears in the control. We will use a property called 'Label'.

...
  <Properties>
    <cor:String Name="Label" cor:String="$Required">
  </Properties>
...


Now we create the control we need...

...
  <Content>
    <Text Name="TextLabel" Color="White" Font="Arial,40"/>
  </Content>
...


And we set up a binding between the property Label and the text control TextLabel.

...
  <Rules>
    <Binding Source="[Label]" Target="TextLabel.Content"/>
  </Rules>
...


OK, that gets us text...but it's bright white! That's not really of any use to us yet. So first, we need to set the alpha property of the text. This chooses how transparent it is going to be. We need the background blue to show through into our interface, so we need something around 25% transparent. So an alpha value of 0.75 (Alpha is a measurement of how VISIBLE an object is, so it's the inverse of the transparency of an object) will do nicely.

    <Text Name="TextLabel" Color="White" Font="Arial,40" Alpha="0.75"/>

Well, it's now transparent, but we have no fade. The last step in this process is to create a CLIP object, which will allow us to make gradient fades around the edges of a defined rectangle.

Clip objects contain all of the objects they will effect, so we need to change the content tag to contain the following...

...
  <Content>
    <Clip Orientation="Vertical" MaximumSize="300,60" FadeSize="26" NearOffset="-40">
      <Children>
        <Text Name="TextLabel" Color="White" Font="Arial,40"/>
      </Children>
    </Clip>
  </Content>
...


The key to the fading is the 'FadeSize', 'Orientation' and 'NearOffset' attributes of the Clip object.

Orientation determines the direction of the fade (eg. since we want the text to fade downwards, Vertical is the obvious solution).

Fadesize is the physical size of the gradient fade. A fadesize of 26 like we have above will make all objects start fading once they are within 26 pixes of the edge of the box.

NearOffset (and FarOffset) adjust the starting places of the gradient fades. In this case, we are moving the NearOffset WAY back. This is so that the TOP of our next does not become faded, but the BOTTOM will be, because we have left FarOffset at it's normal level.

There you have it. A reusable control to start you on your way. Of course, we still need to tweak the font to match the one used in Media Center, but I'll leave that up to you. And when you DO figure it out, could you tell me what it is? I can't find the bugger :)

<UI Name="BackgroundText">
  <Properties>
    <cor:String Name="Label" cor:String="$Required">
  </Properties>

  <Rules>
    <Binding Source="[Label]" Target="TextLabel.Content"/>
  </Rules>

  <Content>
    <Clip Orientation="Vertical" MaximumSize="300,60" FadeSize="26" NearOffset="-40">
      <Children>
        <Text Name="TextLabel" Color="White" Font="Arial,40"/>
      </Children>
    </Clip>
  </Content>

</UI>

Monday, January 29, 2007

Turning UIs into Controls

As I mentioned last post, UI's contain not only content, but also can have their own properties and local variables. We are going to play with those now, to create a more flexible, reusable control.

This time we are creating a text object in a coloured box. We are starting with the code we were using in the last post :

<UI Name="Main">
  <Content>
    <Panel Layout="VerticalFlow">
      <me:BooText>
      <me:BooText>
    </Panel>
  </Content>
</UI>

<UI Name="BooText">
  <Content>
      <Text Content="Boo" Font="Tahoma,30" Color="Blue"/>
  </Content>
</UI>


So the first step is to add our coloured box. This is easy - it's done with a colorfill.

So 'BooText' changes to become...

<UI Name="BooText">
  <Content>
    <Colorfill Content="Red">
      <Text Content="Boo" Font="Tahoma,30" Color="Blue"/>
    </Colorfill>
  </Content>
</UI>


In the above code we have surrounded the text control with a filled red square.

But just saying 'Boo' is very, very boring. We can't expect to reuse a control like that. So now we need to add a property to our BooText UI. And while we are there, let's rename it to 'BGText'.

<UI Name="BGText">
  <Properties>
    <cor:String Name="Label" String="$Required"/>
  </Properties>

  <Rules>
    <Binding Source="[Label]" Target="[MainText.Content]"/>
  </Rules>

  <Content>
    <Colorfill Content="Red">
      <Text Name="MainText" Font="Tahoma,30" Color="Blue"/>
    </Colorfill>
  </Content>
</UI>


Yes, this may need a little bit of explaining.

The first thing we did was declare a new property for this UI. In this case, it's a String (from the cor namespace) named 'Label'. We have set it to the reserved word '$Required' instead of giving it a value (eg. cor:String="My Default Value") which means that the UI that creates this object MUST specify the label.

The label can be assigned either as an attribute (eg. <me:BGText Label="My Label"> or as a tag (eg. <me:BGText><Label>My Label</Label></me:BGText>

In the next part of our UI, we defined a rule. This controls how the control actually responds at runtime. In this case, we have created a binding. We have bound the property called 'Label' to the Content property of the control name MainText. This means that when we pass a value to the Label property of this UI, it will automatically be copied over into the text control named 'MainText'.

Then in our content section, we have given the text element a name (MainText) and removed the Content section, since we will now be giving it content through the Label property.

Last step - change the main UI to reflect our changes.

<UI Name="Main">
  <Content>
    <Panel Layout="VerticalFlow">
      <me:BGText Label="Text #1">
      <me:BGText Label="Text #2">
    </Panel>
  </Content>
</UI>


So we now have two text boxes, one saying "Text #1" and one saying "Text #2", with coloured backgrounds.

Of course, you can play a lot more. You can give the control more properties. For instance, properties to adjust the colour of the text, the colour of the background, the font, etc. Just remember that instead of using the name of the colour (eg. "White") you use the name of the property, in square brackets(eg. "[BackgroundColour]")

<UI Name="BGText">
  <Properties>
    <cor:String Name="Label" String="$Required"/>
    <Color Name="TextColour" Color="White"/>

  </Properties>

  <Rules>
    <Binding Source="[Label]" Target="[MainText.Content]"/>
  </Rules>

  <Content>
    <Colorfill Content="Red">
      <Text Name="MainText" Font="Tahoma,30" Color="[TextColour]"/>
    </Colorfill>
  </Content>
</UI>

What is this UI thing anyway?

OK - Let's talk about UI's.

UI is (of course) short for User Interface. All of your visible controls (text, colorfills, panels, graphics etc.) must be within the 'contents' tag of a UI.

But they are more than just a once-off tag.

For those familliar with .NET programming (and from now on in this blog, I'm going to assume you know the basics of object oriented programming, either C++, Java, C# or J# will do), a UI is also very much like a control class.

Each UI can have properties, local variables, rules of behaviour and it's own appearance. You can use UI's and name them to define a set of reusable controls.

Before we can use a UI, we need to make sure there is a line at the top of our MCML file, one that creates a namespace so we can play with our own UI controls. If you have created your MCML from the wizard in Visual Studio, you may already have it. For those who are hand-writing it, make sure your first tag looks like this...

<Mcml xmlns="http://schemas.microsoft.com/2006/mcml"
xmlns:cor="assembly://MsCorLib/System"
xmlns:me="Me">


OK - so now every UI we create in this document will be in the namespace called 'me' (which is what that whole xmlns:me thing is about.

Now, the first UI is the MAIN UI. This is the one that will automatically be drawn by Media Center.

We will keep our first example very simple. We want two lines of text, both saying 'Boo!' in blue.

<UI Name="Main">
  <Content>
    <Panel Layout="VerticalFlow">
      <Text Content="Boo" Font="Tahoma,30" Color="Blue"/>
      <Text Content="Boo" Font="Tahoma,30" Color="Blue"/>
    </Panel>
  </Content>
</UI>


Or, we could create a new UI, making a reusable control for our text item.

<UI Name="Main">
  <Content>
    <Panel Layout="VerticalFlow">
      <me:BooText>
      <me:BooText>
    </Panel>
  </Content>
</UI>

<UI Name="BooText">
  <Content>
      <Text Content="Boo" Font="Tahoma,30" Color="Blue"/>
  </Content>
</UI>


OK, we didn't save much space this time. But check the next post for how this starts to become useful.

Project 1 - A Basic MCML File

This is the first part of my project. Like all my Media Center interfaces, the new version of Yougle is going to have the same look and feel (or as close as I can get to it, anyway) as the Media Center interface.

But I'm just starting out here, so let's get the basics covered.

Step 1: Make sure Visual Studio 2005 (Express or Pro) is installed. They aren't required for a basic application, but chances are you'll want to write some code to work behind the UI eventually - that, and the fact that Intellisense works for your MCML file in Visual Studio is just plain invaluable.

Step 2: Download and Install the Windows Media Center 5.0 SDK from http://www.microsoft.com/downloads/details.aspx?familyid=a43ea0b7-b85f-4612-aa08-3bf128c5873e&displaylang=en

Step 4: Create a new project in Visual Studio. Once the SDK is installed, you will have a new template under 'Media Center Applications', called 'Windows Media Center Presentation Layer Application'. This will set up a project so you can get started quickly and easily.

Step 5: Now, it's time to write some MCML code. MCML is an XML based language, so all the usual rules to tagging apply. You'll have an MCML application already generated with colour-changing text and a bouncy smiley button. But for now, Let's kill that off and learn a couple of new tags...

<mcml> - Just like the 'html' tag in web pages, this tag is the first one that should appear in any MCML file, after the schema information.

<ui> - This defines a User Interface. These are also used to define new types of reusable control. We will explore this a lot more later. Right now, we just need to get us a working page, so simply know that everything inside a UI tag is part of your user interface.

<text> - This, quite obviously, displays some text.

So, let's get some code in.

<mcml> <ui name="HelloWorld">
<content>
<text content="Hello World" color="White">
</content>
</ui>
</mcml>

There ya' go. A working MCML file, which should give you a 'Hello World' in pretty white, sitting in the middle of the screen.

Don't you feel special?

Next up: Using UI's

Welcome

This blog will hopefully contain a record of all of the stages I've gone through in developing a Media Center application.

If you want any help with an MCML app, feel free to browse the information here - there may be useful source code for you to 'borrow'.

And of course if you see me saying something completely stupid, jump right in and correct me.