|
Windows Definitions and Styles
To create and display its window, Messenger uses two different
kind of files: definition files and style sheet files. Although
each file is used for its own specific reasons, some of the
properties of a window can be defined in both files by using a
different syntax. Here is a quick description of the purpose
of each file.
- Definition File. This is the main file
defining a window, it describes how the window is created and what
elements/controls it contains. It is formatted like an XML file
(although it will not validate against strict XML syntax) with
element tags and attributes. Many elements include sub-elements to
create more complex layouts. An id/class is attached to most
elements to be used in the style file.
-
Style Sheet File. This file
needs to be paired with a definition file to be meaningful. When an
element is declared in the definition file, many of its attributes
can be placed in the style sheet file. This creates a separation
between the bones of the window and its actual look. Style files
work and look like CSS files for web pages.
Note that this section of the documentation is only meant to
introduce you to the windowing system of Messenger. It is not meant
to completely document the way definition and style files are
created for Messenger. Microsoft uses an internal library called
DirectUI for its windows. This library is several years old and has
never been documented for public use by Microsoft so you'll need
patience and determination to make the best out of what you have.
Once you get used to the basics of the system, you'll see that it's
not that difficult to make Messenger display what you want: you
don't need to understand everything, just look at the windows
displayed by Messenger, look at their definition files and figure
out how to make changes by trial and error.
Elements Definition
Let's start with how attributes are defined for the various
elements of a window. Elements are often simply named element but can be called anything else such as
button, urlelem, etc... character case does not matter as
long as you close the element with the exact same name.
Example:
- <element></element> is
valid,
- <Element></Element> is
also valid but
- <element></Element> is
not.
The syntax for sub-elements is identical to XML: each element
needs a matching closing element but can also be closed with an
ending slash if no sub-elements are needed. To demonstrate this,
here are two identical examples:
- <element
id=atom(ai1)></element> allows to include
sub-elements
- <element id=atom(ai1) /> is
closed and cannot contain sub-elements.
In the example above, id is an
attribute and atom(ai1) is the value of
the attribute. Once again, this works like in XML except that
values are not enclosed in quotes if they don't refer to strings.
The list of attributes available for each element depends on the
element's kind, however, you'll find two attributes with a basic
general use: id and class. Case does not matter here either so
id can also be written Id or ID. These two
attributes are used to match elements with their respective styles
and to help Messenger identify which is which. The value of these
attributes will often be a strong hint of what the element is
about. Examples:
<element class="WindowLogo" ID=Atom(ai198)/>
<element id=atom(idSearchTextBackground) padding=rect(4,0,3,0) Height=0/>
In the first element, both a class and an ID are specified.
Hopefully in this case, the class name is enough to understand that
the element is about displaying the logo of the window. However,
many other elements use numeric ids that are meaningless on their
own. In such a case, you'll need to check the style file to find
more information about the element.
Elements Styles
Style sheet files are organized with simple structures: for each
element listed in the file, one or more attribute is specified.
Attributes generally apply to specific elements based on their id
and/or class and can also depend on some other attributes or
internal states. Let's take a look at this example:
button[id=atom(accountStatusbtn)]
{
AccDefAction:"Press";
ShortcutString:"Account &information";
}
Each block of style is defined the same way: the first line
identifies the condition for the style to be applied and the
following attributes are placed between {
} brackets. The first word of the first line is the
element's name. In this case, the element's name is button meaning that this style will apply to
elements defined as <button> in
the definition file. Following the element's name is 0, 1 or more
condition, each one specified between [
]. The conditions can be two things:
- An attribute value. This is what you'll see
the most in style sheet files. Attributes specified as condition
will often be id or class but can also be anything else recognized by
the element. Attribute conditions are written using the
[name=value] syntax.
- An internal state. Internal states give real
purpose to the style sheet files by allowing attributes to vary
depending on the state of an element. States are indicated on their
own without an attached value and their meaning is often
straightforward. For example, [pressed]
specifies that the attributes should be applied when the element is
pressed (generally by clicking on it).
In the example above, one attribute value condition is specified
as id=atom(accountStatusbtn). This
means that the attributes specified between brackets will be
applied to any element defined as <button
id=atom(accountStatusbtn) ...>. Because this is the most
important part of style files to understand, let's analyze two
other examples:
button[class="WebcamStatusBtn"][enabled=false]
{
alpha:128;
}
wledit[id=atom(WindowEmail)][keyfocused]
{
contentalign:middleleft;
}
Can you guess what elements are touched by these styles before
reading the answer? :-)
The first example has two conditions based on an attribute
value. This simply means that for the style to be applied, a
button element must be defined with
class="WebcamStatusBtn" and be
disabled. Note that attributes such as enabled can be changed at runtime by Messenger.
This means that any element defined as <button class="WebcamStatusBtn" ...> can be
touched by this style if Messenger disables the element after its
creation. Of course, any element defined as <button class="WebcamStatusBtn" enabled=false
...> would use this style by default. Also, remember that
attributes can be specified in any order so <button ... enabled=false ...
class="WebcamStatusBtn"> would also receive this
style.
The second example uses an internal state condition. This means
that any <wledit
id=atom(WindowEmail)> element that's considered being
keyfocused will use this style. This
kind of condition is useful to allow elements to change on their
own following an action from the user. For example, buttons often
use the pressed condition to look
different when pressed or keyfocused to
display a hint indicating that a control is currently active (if a
keyboard is used instead of a mouse to select the control).
Styles in Definition Files
Because styles are just groups of attributes, every attribute
that's specified in a style sheet file can also be specified
directly in the definition file. Let's consider the following
example of a style block and a matching definition:
button[id=atom(accountStatusbtn)]
{
AccDefAction:"Press";
ShortcutString:"Account information";
}
<button class="HIGToolbarButton" id=atom(accountStatusbtn) cmdid=692>
The style can be merged in the definition file simply by
replacing : with
= to create compatible
attribute syntax.
<button class="HIGToolbarButton" id=atom(accountStatusbtn) cmdid=692
AccDefAction="Press" ShortcutString="Account information">
If this line was used in the definition file and the style was
removed from the style sheet file, the end result would still be
the same. Styles are just that: extra attributes added to each
element. One of the main reasons why you can't simply get rid of
style files altogether is the use of internal state conditions.
These conditions cannot be expressed in a definition file. This
means that you need a style file to declare different attributes
for different states as mentioned above with the wledit example. Also, because styles can be
combined, it is sometimes practical to set some general conditions
in the style sheet file. For instance:
button[enabled=false]
{
foreground:rgb(193,193,193);
}
This would be useful to specify that any button (no id or class
was specified) that's disabled uses a different foreground color
defined as foreground=rgb(193,193,193).
To specify a color that's based on the user's chosen color (which
is blue by default), you'll need to check out the <Colors> elements in SkinInfo as colorized
colors cannot be specified as data in Style Sheet files (these
colors use a single Intensity attribute which modifies the
brightness of the original RGB).
What's next?
To practice is to learn so if modifying the heart of Messenger
windows is a subject that interests you, practice, practice, and
practice again. The contact list's logon frame is a good starting
point to experiment. Edit its files to reorganize elements and
change some of the styles it uses. This window is not that
complicated to decipher and it's the first one you see when
starting Messenger (testing requires a lot of restarting so you
won't want to spend too much time signing back-in if all you want
to do is test some general ideas). Also, before jumping to any
other section of this documentation, make sure to read about
the trace file, it will save you a lot
of time when things don't go as planned after editing one of
Messenger's files.
Remember that when modifying definition files, it is always
better not to remove whole elements from the original file. If you
want to visually remove an element from a window, add a
"visible=false" or "height=0" attribute. This way, Messenger will still
be able to locate the element but it won't appear on screen. This
is important to prevent internal problems and crashes. In cases
where removing an element is inevitable, make sure to double your
tests.
Replacing definition files and style files in your skininfo file
is achieved by adding <Definition> and <Style> elements. Text files must be encoded
in ANSI as Messenger does not support Unicode in this case. Also,
instead of using text files, definition and style data can be
embedded directly into skininfo by using the <Data> element (this not recommended if you
want to keep things easy to maintain). Here is an example showing
how to replace the files of the contact picker window (ids taken
from Messenger 8.5) :
<Resources><Replace>
<Windows>
<Definitions>
<Definition Id="45703">
<File>contactpicker_newdef.txt</File>
</Definition>
</Definitions>
<Styles>
<Style Id="45703">
<File>contactpicker_newstyle.txt</File>
</Style>
</Styles>
</Windows>
</Replace></Resources>
One thing you'll need to learn to create good looking windows is
the way to manipulate pictures in your files. This big subject is
waiting for you in Using Pictures but
remember to practice what you learnt here first!
See Also
Skins Essentials, The Trace
File, Using Pictures.
|