Difference between revisions of "Theming MythNews"

From MythTV Official Wiki
Jump to: navigation, search
(The Buttonlist Widget)
(The Buttonlist Widget)
Line 361: Line 361:
 
             </textarea>
 
             </textarea>
 
             <statetype name="buttoncheck">
 
             <statetype name="buttoncheck">
                 <position>91%,5</position>
+
                 <position>92%,11</position>
 
                 <state type="off">
 
                 <state type="off">
 
                     <imagetype name="checkoff">
 
                     <imagetype name="checkoff">
Line 408: Line 408:
 
*We add the states "selected" and "inactive" and inherit everything but their backgrounds from "active."
 
*We add the states "selected" and "inactive" and inherit everything but their backgrounds from "active."
 
*We close all our tags
 
*We close all our tags
 +
 +
To complete this widget, you will need to create the following images:
 +
 +
*widebuttonbackground.png (Unselected Button, 349x50)
 +
*widebuttonbackground_selected.png (Selected Button, 349x50)
 +
*rightarrow.png (Submenu button, 37x37)
 +
*lb-check-empty.png (Empty checkbox, 37x37)
 +
*lb-check-half.png ("Half Checked" checkbox, 37x37)
 +
*lb-check-full.png (Fully checked checkbox, 37x37
  
 
==Editing the news-ui.xml file==
 
==Editing the news-ui.xml file==
  
 
MythTV will always attempt to load needed files from your theme's directory.  If it fails to find them, however, it will fall back to files contained in the default (for 4:3 themes) and default-wide (for 16:9 themes) directories.  If a wide theme is unable to find a file in default-wide, it will try default.  Presently, most of the legacy themes do not have custom versions of the new MythUI screens, and are falling back to the default themes.  This is true with MythNews as well.  Because of this, the legacy themes do not contain the required news-ui.xml file.  We will need to create a new one.
 
MythTV will always attempt to load needed files from your theme's directory.  If it fails to find them, however, it will fall back to files contained in the default (for 4:3 themes) and default-wide (for 16:9 themes) directories.  If a wide theme is unable to find a file in default-wide, it will try default.  Presently, most of the legacy themes do not have custom versions of the new MythUI screens, and are falling back to the default themes.  This is true with MythNews as well.  Because of this, the legacy themes do not contain the required news-ui.xml file.  We will need to create a new one.

Revision as of 16:56, 27 April 2009

This basic tutorial will explain how to theme a MythUI plugin from start to finish, for the absolute beginner.

Part I: Required Widgets

Basic understanding of the following widgets is necessary. You don't need to understand everything, but you will need a basic knowledge of their purpose.

  • Textarea
  • Textedit
  • Button
  • Buttonlist
  • Imagetype
  • Checkbox

Before continuing further, read the section on the MythUI Theme Development page on each of them.

Part II: The Tutorial

MythNews is a very simple plugin. It's easy to theme and covers most of the essential theming concepts. You may wish to have the News-ui.xml page open in a browser for your reference. Each plugin and component of MythTV has an XML theme file associated with it, and each of those files will be documented in the wiki. Each named attribute, the widget type, and a brief description of the item will be documented.

For your first foray into theming, you will probably want to start by editing an existing theme. Go to the MythTV share directory on your frontend (Usually /usr/share/mythtv/themes or /usr/local/share/mythtv/themes) and make a backup copy of G.A.N.T.

cp -rf "G.A.N.T" "G.A.N.T-backup"

Editing the base.xml file

Now we have a copy of the theme directory for safety, and we can begin editing the original. Enter the G.A.N.T directory and edit the base.xml file with an editor of your choice. The base.xml is like an "include" file for the rest of your theme. You can save yourself tons of time by defining widgets, fonts, and windows in the base.xml file and then insert them later with a few lines of XML.

We're going to create all the widgets listed above to use later.

The Textarea Widget

We're not actually going to create a textarea in the base.xml , but we are going to define a font that we can use later in a textarea. Scroll to the bottom of the base.xml file, and just before the end of the theme file (</mythuitheme>) let's add the following text:

<font name="newsfont" face="Arial">
    <size>11</size>
    <color>#ffffff</color>
</font>

There are lots of attributes you can add to your text, and they are all thoroughly discussed on the MythUI Theme Development page, but these are the absolute basics. We defined a font name (newsfont), a font face (Arial), a size (11), and a color in hexadecimal notation (#ffffff is white). Now, when we create a textarea later, we'll be able to do something like this (Note: this is an example, don't put this in your base.xml):

<textarea name="sometextarea">
    <font>newsfont</font>
    <value>I am some text, using the style you defined!</value>
</textarea>

The Textedit Widget

For the settings screens in MythNews, we're also going to need to define a text edit box. Before we start on the code, go to your graphics editing program and create the following images:

After your font definition from above, but before the </mythuitheme>, let's add the following text:

<textedit name="newstextedit">
    <area>0,0,287,28</area>
    <statetype name="background">
        <state name="active">
            <imagetype name="background">
                <filename>textedit_background.png</filename>
            </imagetype>
        </state>
        <state name="selected">
            <imagetype name="background">
                <filename>textedit_background_selected.png</filename>
            </imagetype>
        </state>
        <state name="inactive">
            <imagetype name="background">
                <filename>textedit_background_grey.png</filename>
            </imagetype>
        </state>
    </statetype>
    <imagetype name="cursor">
        <filename>cursor.png</filename>
    </imagetype>
    <textarea name="text">
        <area>3,5,281,22</area>
        <font>newsfont</font>
    </textarea>
</textedit>

The textedit may look complicated, but it's actually pretty simple. Let's break it down line by line:

<textedit name="newstextedit">

We create a textedit widget called "newstextedit."

<area>0,0,287,28</area>

We specify an area. The format is x,y,width,height. The x and y coordinates are measured from the top left corner of the screen, but we'll set these to 0 because we're not actually placing it on screen at the moment, just defining it for use later. Later, when we use a textedit and have it inherit from this textedit, we can override any or all attributes by specifying them there. Our default textedit is going to be 287 pixels wide and 28 pixels tall.

<statetype name="background">

A statetype is a special type of widget that we use in other widgets. A statetype is basically a widget that behaves differently according to conditions. For example, we want our textarea to look different when it's selected, unselected, or greyed out. The statetype name for the backgroun in a textedit is hardcoded as "background." For your textedit to work properly, the statetype (and subsequent states) must be named exactly like this. Now let's define the

<state name="active">
    <imagetype name="background">
        <filename>textedit_background.png</filename>
    </imagetype>
</state>

Statetypes contain states. Active, Selected, and Inactive are hardcoded state names used in a textarea. We need all three states in our "background" statetype for our textarea to work. They represent the active but not in use, active and in use, and greyed out states, respectively. In each state we're going to add an imagetype widget. We are basically using a different image of our text area for each state, which myth will display based on which condition the textedit is in. The three files in use here are:

  • textedit_background.png
  • textedit_background_selected.png
  • textedit_background_grey.png

In your preferred graphics package (Photoshop, The GIMP, etc.) create each of these files as a 287x28 pixel PNG. You can design them however you like, just do your best to make them represent the states. Make sure to copy or save the files into the theme directory.

<imagetype name="cursor">
    <filename>cursor.png</filename>
</imagetype>

Our textedit also needs an image called "cursor." In your graphics package, create a cursor image that fits nicely inside the 287x28 pixel areas you created above. Save it as cursor.png in your theme directory.

<textarea name="text">
    <area>3,5,281,22</area>
    <font>newsfont</font>
</textarea>

Of course, our textedit needs a space for the text to go. In this case, it needs to be called "text." Because the textarea is being created within another widget, you will see that the area is relative to the top left of the widget. We're going to place the text area just slightly down and to the right from that corner, and it will be slightly smaller width and heightwise. We're also doing to need to set a font. Look, it's the font we created above, newsfont! This is the first example we see of inheritance in action. Rather than defining the whole font again, we just call the font name, which inherits all those attributes.

</textedit>

Finally, we close our textedit widget.

The Button Widget

The button widget is a very simple widget. Let's add the following widget after our textarea from above:

<button name="newsbutton">
    <area>0,0,150,35</area>
    <statetype name="buttonstate">
        <state name="active">
            <imagetype name="background">
                <area>0,0,150,35</area>
                <filename>buttonbackground.png</filename>
            </imagetype>
            <textarea name="text">
                <area>5,5,140,30</area>
                <align>allcenter</align>
                <font>newsfont</font>
            </textarea>
        </state>
        <state name="selected" from="active">
            <imagetype name="background">
                <area>0,0,150,35</area>
                <filename>buttonbackground_selected.png</filename>
            </imagetype>
        </state>
        <state name="disabled" from="active" />
        <state name="pushed" from="active">
            <imagetype name="background">
                <area>0,0,150,35</area>
                <filename>buttonbackground_pushed.png</filename>
            </imagetype>
        </state>
    </statetype>
</button>

Let's break the button widget down to its component parts again.

<button name="newsbutton">
    <area>0,0,150,35</area>

We create a button widget named "newsbutton." Our default button will have dimensions of 150 pixels wide by 35 pixels tall.

<statetype name="buttonstate">

Just as above, we have a required statetype named "buttonstate." A statetype named buttonstate must exist and must contain states active, selected, disabled, and pushed.

<state name="active">
    <imagetype name="background">
        <area>0,0,150,35</area>
        <filename>buttonbackground.png</filename>
    </imagetype>
    <textarea name="text">
        <area>5,5,140,30</area>
        <align>allcenter</align>
        <font>newsfont</font>
    </textarea>
</state>

Here is our first state, "Active." Active is an available (but not selected) button. We're going to add an image of an unselected button (buttonbackground.png) that is 150x35 pixels, and a text area inside that button. Here we use the <align> tag to center the text within the button, and our "newsfont" font.

<state name="selected" from="active">
    <imagetype name="background">
        <area>0,0,150,35</area>
        <filename>buttonbackground_selected.png</filename>
    </imagetype>
</state>

Our second state is "selected." In this case, we've decided to be lazy. We want to use the exact same textarea, we just want the background image to be different. so we added from="active" to inherit everything from the active state, and just redefined the imagetype.

<state name="disabled" from="active" />

Here again we've chosen to inherit the whole disabled state from the active state.

<state name="pushed" from="active">
    <imagetype name="background">
        <area>0,0,150,35</area>
        <filename>buttonbackground_pushed.png</filename>
    </imagetype>
</state>

Our final state is the "pushed" state. We again inherit the button from "active," and override it with a new image background.

    </statetype>
</button>

With all our required states defined, we can close our statetype, and our button. Make sure to create the three images we defined above as 150x35 pixel PNGs. They are:

  • buttonbackground.png
  • buttonbackground_selected.png
  • buttonbackground_pushed.png

The Buttonlist Widget

The buttonlist widget is the most complicated widget we'll use in our tutorial, but it's nothing we haven't already dealt with. Below our button definition from above, let's add the following code:

<buttonlist name="newsbuttonlist">
    <area>0,0,349,250</area>
    <layout>vertical</layout>
    <spacing>3</spacing>
    <scrollstyle>free</scrollstyle>
    <wrapstyle>items</wrapstyle>
    <buttonarea>0,0,100%,97%</buttonarea>
    <statetype name="buttonitem">
        <state name="active">
            <area>0,0,100%,30</area>
            <imagetype name="buttonbackground">
                <filename>widebuttonbackground.png</filename>
            </imagetype>
            <textarea name="buttontext">
                <area>5,10,85%,30</area>
                <font>newsfont</font>
                <cutdown>yes</cutdown>
                <align>allcenter</align>
            </textarea>
            <statetype name="buttoncheck">
                <position>91%,5</position>
                <state type="off">
                    <imagetype name="checkoff">
                        <filename>lb-check-empty.png</filename>
                    </imagetype>
                </state>
                <state type="half">
                   <imagetype name="checkhalf">
                        <filename>lb-check-half.png</filename>
                    </imagetype>
                </state>
                <state type="full">
                    <imagetype name="checkfull">
                        <filename>lb-check-full.png</filename>
                    </imagetype>
                </state>
            </statetype>
            <imagetype name="buttonarrow">
                <position>92%,11</position>
                <filename>rightarrow.png</filename>
            </imagetype>
        </state>
        <state name="selected" from="active">
            <imagetype name="buttonbackground">
                <filename>widebuttonbackground_selected.png</filename>
                <alphapulse min="200" max="255" change="1"/>
            </imagetype>
        </state>
        <state name="inactive" from="active">
            <imagetype name="buttonbackground">
                <filename>widebuttonbackground_selected.png</filename>
                <alpha>127</alpha>
            </imagetype>
        </state>
    </statetype>
    <statetype name="upscrollarrow">
        <position>10,97%</position>
        <state type="off">
            <imagetype name="upon">
                <filename>uparrow.png</filename>
                <alpha>90</alpha>
            </imagetype>
        </state>
        <state type="full">
            <imagetype name="upoff">
                <filename>uparrow.png</filename>
            </imagetype>
        </state>
    </statetype>
    <statetype name="downscrollarrow">
        <position>40,97%</position>
        <state type="off">
            <imagetype name="dnon">
                <filename>downarrow.png</filename>
                <alpha>90</alpha>
            </imagetype>
        </state>
        <state type="full">
            <imagetype name="dnoff">
                <filename>downarrow.png</filename>
            </imagetype>
        </state>
    </statetype>
</buttonlist>

The above may look a little daunting, but the buttonlist is just a couple of special tags that establish the behavior of the button list, and four statetypes. Since you've already created a statetype and understand what they do, let's break this widget definition down by chunks.

<buttonlist name="newsbuttonlist">
    <area>0,0,349,250</area>
    <layout>vertical</layout>
    <spacing>3</spacing>
    <scrollstyle>free</scrollstyle>
    <wrapstyle>items</wrapstyle>
    <buttonarea>0,0,100%,97%</buttonarea>
  • We create a new button list called "newsbuttonlist."
  • <area> - The default size of the button list (bearing in mind that we can override this later) is 349 pixels wide by 250 pixels tall.
  • <layout> - defines the list as a vertical buttonlist (we could also use horizontal or grid, but for this button list, we will do something traditional).
  • <spacing> - establishes the number of pixels which should be left between each button item.
  • <scrollstyle> - is a tag which sets how the scrolling of the list behaves-- "free" allows the selector to move freely through the list. If we used "center," the selected item would remain in the center and the list would float around it.
  • <wrapstyle> - establishes what happens when you get to the end of the list. We chose "items" because we want the last item in the list to wrap back to the first (other options are selection and none).
  • <buttonarea> - Sets the amount of the overall widget space to be devoted to the buttons. Here you'll see the first example of using percentages instead of pixels. This will maintain a consistent layout without having to change this pixel for pixel each time we use the widget at a different size.
    <statetype name="buttonitem">
        <state name="active">
            <area>0,0,100%,50</area>
            <imagetype name="buttonbackground">
                <filename>widebuttonbackground.png</filename>
            </imagetype>
            <textarea name="buttontext">
                <area>5,10,85%,30</area>
                <font>newsfont</font>
                <cutdown>yes</cutdown>
                <align>allcenter</align>
            </textarea>
            <statetype name="buttoncheck">
                <position>92%,11</position>
                <state type="off">
                    <imagetype name="checkoff">
                        <filename>lb-check-empty.png</filename>
                    </imagetype>
                </state>
                <state type="half">
                   <imagetype name="checkhalf">
                        <filename>lb-check-half.png</filename>
                    </imagetype>
                </state>
                <state type="full">
                    <imagetype name="checkfull">
                        <filename>lb-check-full.png</filename>
                    </imagetype>
                </state>
            </statetype>
            <imagetype name="buttonarrow">
                <position>92%,11</position>
                <filename>rightarrow.png</filename>
            </imagetype>
        </state>
        <state name="selected" from="active">
            <imagetype name="buttonbackground">
                <filename>widebuttonbackground_selected.png</filename>
                <alphapulse min="200" max="255" change="1"/>
            </imagetype>
        </state>
        <state name="inactive" from="active">
            <imagetype name="buttonbackground">
                <filename>widebuttonbackground_selected.png</filename>
                <alpha>127</alpha>
            </imagetype>
        </state>
    </statetype>

This looks almost exactly like our button from above!

  • We create the required statetype "buttonitem."
  • We add the required state "active."
  • In active, we create the buttonbackground imagetype (for a button that is unselected but available). The filename is widebuttonbackground.png.
  • We add a textarea widget for the text of our buttons. The area is set to use 85% of the width, and 30 pixels tall. The <cutdown> tag will truncate the text with ellipsis (...) if necessary. <align> sets the text to be centered within the button.
  • The buttonlist needs a sub-statetype called "buttoncheck." Buttoncheck contains three states, off, half, and full. These are checkboxes that indicate whether a selection at a lower level is unselected, partially selected, or fully selected. One example of this is the playlist selection lists in MythMusic.
  • We add the required "buttonarrow" imagetype to the button. This image will appear to indicate the button has a submenu. It appears conditionally (ie, only when needed).
  • We add the states "selected" and "inactive" and inherit everything but their backgrounds from "active."
  • We close all our tags

To complete this widget, you will need to create the following images:

  • widebuttonbackground.png (Unselected Button, 349x50)
  • widebuttonbackground_selected.png (Selected Button, 349x50)
  • rightarrow.png (Submenu button, 37x37)
  • lb-check-empty.png (Empty checkbox, 37x37)
  • lb-check-half.png ("Half Checked" checkbox, 37x37)
  • lb-check-full.png (Fully checked checkbox, 37x37

Editing the news-ui.xml file

MythTV will always attempt to load needed files from your theme's directory. If it fails to find them, however, it will fall back to files contained in the default (for 4:3 themes) and default-wide (for 16:9 themes) directories. If a wide theme is unable to find a file in default-wide, it will try default. Presently, most of the legacy themes do not have custom versions of the new MythUI screens, and are falling back to the default themes. This is true with MythNews as well. Because of this, the legacy themes do not contain the required news-ui.xml file. We will need to create a new one.