制作Skin -- MPlayer -- Linux下的电影播放器

# 附录D - MPlayer skin的格式

本文件的目的是描述MPlayer的skin的格式。这里所包含的信息可能不对，因为

1. GUI不是我写的
2. GUI还没有完成
3. 我可能搞错了

因此如果某个功能与它在这里被描述的工作方式不一样，不用大惊小怪

。

谢谢Zolt醤 Ponekker的帮助。

Andr醩 Mohari <mayday@freemail.hu>

## D.1 综述

这虽然与skin的格式扯不上什么关系，但是你应该了解MPlayer有没有内建的皮肤， 因此为了能够使用GUI必须安装至少一种皮肤。

### D.1.1 目录

skin的搜索目录(按顺序)是：

        $(DATADIR)/skins/
        $(PREFIX)/share/mplayer/skins/
        ~/.mplayer/skins/

注意，第一个路径倚赖于MPlayer的安装配置(见`configure`脚本 的`--prefix`和`--datadir`的参数)。

所有的skin被安装到上面列出的一个目录下的自己的目录中，例如：

        $(PREFIX)/share/mplayer/skins/default/

### D.1.2 图像格式

图像必须是真彩的(24或者32bpp)PNG图片。

在主窗口(见下面)中你能使用包含“透明色”的图像：用颜色#FF00FF(深红) 填充的区域在MPlayer看来是完全透明的。这意味着你甚至能改变窗口外形如果你的X服务器有XShape扩展。

### D.1.3 Skin的组成部分

Skin的格式是十分自由的(不是像Winamp/XMMS的那种固定格式的皮肤)，所以能不能做出些东西取决于你。

目前有三个要被修饰的窗口：主窗口，副窗口,播放条和 Skin菜单(右键单击弹出)。

- 主窗口和/或者播放条是你控制MPlayer的地方。窗口的背景是图像。各种项目可以(而且必须)被放置在这里： 按钮，滑动条和标签。对于每一个项目，你都必须指定其位置和大小。

  一个按钮有三种状态(按下，释放，禁止)，所以按钮图像必须垂直地划分成三部分。 细节参见按钮项目。

  滑动条(主要用于搜寻条和音量/平衡控制)可以有任意多的状态只要你把图像分成上下排列的足够多份。 细节参见hpotmeter和potmeter。

  标签有一点特殊：字符需要从图像文件中绘制，而图像中的字符用字体描述文件描述。 后者一个纯文本文件规定图像中每一字符的x，y坐标和大小(图像文件和他的字体描述文件共同 组成一个字体)。细节参见dlabel和slabel。

  注意：所有图像都能像图像格式一节中说明的使用透明色。如果X Server不支持 XShape扩展，透明的部分将显示为黑色。如果你想使用这个特性，主窗口背景图像的宽度应该能被8整除。

- subwindow是电影显示的地方。如果没有载入电影它将显示一个指定的图像(空的窗口太无聊了:-)) 注意：在这里不允许使用透明色。

- skin菜单仅仅是提供一个通过菜单控制MPlayer的方法。菜单需要两个图像：一个是基础图像 用来显示菜单的正常状态，另一个用来显示被选择的项目。当菜单弹出时，显示第一个图像。如果你把鼠标在 菜单条目上移动，当前选择的项目从第二个图像中复制并覆盖到当前鼠标指针下面的菜单项目上。 (第二个图像从来不作为整体来显示)。

  一个菜单选项用图像中的位置和大小定义(细节参见skin菜单)。

还有一件重要的事情没有提到：为了使按钮，滑动条和菜单项工作，MPlayer必须知道如果他们被点击 的话应该做什么。这是利用消息(事件)机制完成的。对于这些项目，你必须定义当 他们被点击时将会产生的消息。

### D.1.4 文件

你需要制作下列的文件构成一个skin：

- 一个配置文件称为skin，告诉MPlayer如何将skin的不同部分放在一起， 以及如果你在窗口中某处点击的话应该做什么。
- 主窗口的背景图像。
- 主窗口上代表物件的图像(包括一个或更多字体描述文件用来显示标签)。
- 在副窗口中显示的图像(可选)。
- skin菜单的两个图像(仅当你想要创建菜单时才需要他们)。

除了skin的配置文件之外，你能给其它文件起随便什么名字(但字体描述文件必须以`.fnt`为扩展名)。

## D.2 skin文件

如上所述，这是skin的配置文件。 它是基于行的；注释行必须以'`;`'开头(只有空格和tab可以放在'`;`'之前)。

文件由section组成。每一段描述一个程序的skin，使用下列的形式：

    section = section name
    .
    .
    .
    end

目前只有一个程序，所以你只需要一个section： 它的名称是movieplayer。

这个段中每个窗口用下列形式的块描述：

    window = window name
    .
    .
    .
    end

其中window name可以是下面各字串中的一项：

- main -- 对于主窗口
- sub -- 对于副窗口
- menu -- 对于skin菜单
- playbar - 播放条

(副窗口和skin菜单块是可选的 -- 你不一定要创建菜单或者修饰副窗口 )。

在一个窗口的描述块内，你能用下列形式的一行定义窗口中的每一项目：

`item = parameter`
  其中`item`是定义GUI项目的类型的字串，`parameter`是一个数字或者文字值 (或者一组用逗号分开的值的列表)。

把上述的放在一起，整个文件看起来就有点像这样：

    section = movieplayer
      window = main
      ; ... items for main window ...
      end

      window = sub
      ; ... items for subwindow ...
      end

      window = menu
      ; ... items for skin menu ...
      end

      window = playbar
      ; ... items for playbar ...
      end
    end

图像文件的名称必须不带目录名 -- 图像在`skins`目录中被搜索。你能(但是并不需要)规定扩展名。 如果文件不存在，MPlayer将试图装载`<filename>.<ext>`文件， `<ext>`可以是`png`或者`PNG`(按这个顺序尝试)。第一个匹配文件将被使用。

最后是一些用来定位的语句。主窗口和副窗口可以放置在屏幕的不同的角落，通过给定`X`和`Y`坐标。 `0`代表顶端或左端，`-1`代表中心然后`-2`代表右边或底部：

    (0, 0)----(-1, 0)----(-2, 0)
      |          |          |
      |          |          |
    (0,-1)----(-1,-1)----(-2,-1)
      |          |          |
      |          |          |
    (0,-2)----(-1,-2)----(-2,-2)

这里有个例子可以把这个搞清楚。假设你有个叫`main.png`的图像用来做主窗口： `base = main, -1, -1` MPlayer将尝试装载`main`，`main.png`，`main.PNG`文件。

### D.2.1 主窗口和播放条

下面是所有能用于'`window = main`' . . . '`end`'和'`window = playbar`' . . '`end`'块中的项目的列表。

`base = image, X, Y`
  指定用于主窗口的背景图像。窗口将显示在屏幕上的`X，Y`位置，窗口的大小与图像相同。
  注意：这些参数目前对显示窗口不起作用。
  警告：图像中的透明区域(彩色的#FF00FF )在没有XShape扩展的X服务器上是 黑色的。图像的宽度必须能被8整除。
`button = image, X, Y, width, height, message`
  将一个大小为`width`*`height`的按钮放置在`X`，`Y`的位置。 指定的`message`将在按钮被点击时产生。被`image`制定的图像必须有从上到下三个部分 (根据按钮的可能状态)，像这样：

      +------------+
      |  pressed   |
      +------------+
      |  released  |
      +------------+
      |  disabled  |
      +------------+

`decoration = enable|disable`
  允许或禁止window manager修饰主窗口。缺省设定是禁止。
  注意：这对显示窗口无效，它们不需要。
`hpotmeter = button, bwidth, bheight, phases, numphases, default, X, Y, width, height, message`
`vpotmeter = button, bwidth, bheight, phases, numphases, default, X, Y, width, height, message`
  在`X`，`Y`位置放置一个大小为`width`*`height`的水平滑动条。 所用的图像可以划分成不同的部分用来显示滑动条的不同状态(例如，你能做一个音量滑动条，当音量从最小变到最大时， 滑动条的颜色从绿色变成红色。)。`hpotmeter`可以有一个能被水平拖曳的按钮。
  参数是：
  - `button` -- 用于按钮的图像(必须有从上到下三部分，跟button中一样)
  - `bwidth`，`bheight` -- 按钮的大小
  - `phases` -- 用于hpotmeter的不同的状态的图像。如果你想不要这样的图像可以使用一个特殊的值`NULL`。 图像必须像这样被垂直划分成`numphases`个部分：

        +------------+
        |  phase #1  |
        +------------+
        |  phase #2  |
        +------------+
             ...
        +------------+
        |  phase #n  |
        +------------+

  - `numphases` -- `phase`图像中储存的状态的数量
  - `default` -- hpotmeter的缺省值(范围0到100)
  - `X`，`Y` -- hpotmeter的位置
  - `width`，`height` -- `hpotmeter`的宽度和高度
  - `message` -- 当`hpotmeter`的值改变时产生的消息
`potmeter = phases, numphases, default, X, Y, width, height, message`
  没有按钮的`hpotmeter`。(我猜它是用来旋转，但它只对水平拖拽作出反应)。 描述参数参见hpotmeter。`phases`能设为`NULL`， 但这实在没什么用处，因为那样你就看不到`potmeter`在哪里了。
`font = fontfile, fontid`
  定义一个字体。`fontfile`是以`.fnt`为扩展名的字体描述文件的名字(不要加上扩展名)。 `fontid`用来代表这种字体(见dlabel和slabel)。 可以定义25个字体。
`slabel = X, Y, fontid, "text"`
  在`X`，`Y`位置放置一个静态的标签。`text`将用`fontid`代表的字体显示。 text只能是无格式文本(`$x`之类的变量不起作用)而且必须封在一对双引号中(但是`"`字符不能是text的一部分)。 标签使用由`fontid`代表的字体显示。
`dlabel = X, Y, length, align, fontid, "text"`
  在`X`，`Y`位置放置一个动态的标签。标签被称为动态的，因为它的text周期性地刷新。标签的最大限度长度由 `leghth`给定(它的高度是字符的高度)。如果将要显示的text比给定的宽度宽，它将滚动显示，否则它将在指定的空间之内按 `align`参数的值对齐显示：`0`表示靠右对齐，`1`表示居中对齐，`2`表示靠左对齐。
  要显示的文本由`text`给定：text必须封在一对双引号中(但是`"`字符不能是text的一部分)。标签使用由 `fontid`代表的字体显示。你能在文本中使用下列变量：

  Variable | Meaning
  --- | ---
  `$1` | hh:mm:ss格式的播放时间
  `$2` | mmmm:ss格式的播放时间
  `$3` | hh(小时)格式的播放时间
  `$4` | mm(分)格式的播放时间
  `$5` | ss(秒)格式的播放时间
  `$6` | hh:mm:ss格式的电影长度
  `$7` | mmmm:ss格式的电影长度
  `$8` | h:mm:ss格式的电影长度
  `$v` | xxx.xx%格式的音量
  `$V` | xxx.x格式的音量
  `$b` | xxx.xx%格式的声道平衡
  `$B` | xxx.x格式的声道平衡
  `$$` | `$`字符
  `$a` | 一个代表音频格式的字母(none: `n`，mono: `m`，stereo: `t`)
  `$t` | track号(在播放列表中)
  `$o` | 文件名
  `$f` | 小写格式文件名
  `$F` | 大写格式文件名
  `$T` | 一个代表媒体流类型的字幕(文件: `f`，Video CD: `v`，DVD: `d`，URL: `u`)
  `$p` | "p"字符(如果电影正在播放并且字体中有"p"这个字符)
  `$s` | "s"字符(如果电影停止播放并且字体中有"s"这个字符)
  `$e` | "e"字符(如果playback被暂停并且字体中有"e"这个字符)
  `$x` | 电影宽度
  `$y` | 电影高度
  `$C` | 使用的编解码器的名字

  注意：`$a`，`$T`，`$p`，`$s`和`$e`变量都返回应该被显示作为特殊的符号 (例如，"e"通常代表像`||`这样的暂停符号)的字符。你应该有一个正常字符的字体以及另一个用于符号的不同的字体。 更多信息参见符号部分。

### D.2.2 副窗口

下列的项目能用于'`window = sub`' . . . '`end`'块。

`base = image, X, Y, width, height`
  在副窗口中将要显示的图像。窗口将在屏幕给定的`X`，`Y`位置出现(`0,0`是左上角)。 你能用`-1`指定中心`-2`指定右边(`X`)和底部(`Y`)。窗口将和图像一样大。 `width`和`height`指定窗口的大小； 他们是可选的(如果没有他们，窗口是与图像同样的大小)。
`background = R, G, B`
  让你设置背景颜色。它在图像小于窗口时有用。 `R`，`G`和`B`规定颜色的的红，绿和蓝色的组成部分(它们中每一个都是从0到255的十进制数字)。

### D.2.3 Skin菜单

如前所述，菜单用两个图像显示。 正常的菜单条目从`base`项指定的图像中获得，当前选择的条目则从`selected`项指定的图像中获得。 你必须通过`menu`项定义每个菜单条目的位置和大小。

这些是能用于'`window = menu`'. . . '`end`'之间的项目。

`base = image`
  正常的菜单条目的图像。
`selected = image`
  所有条目都被选择的菜单的图像。
`menu = X, Y, width, height, essage`
  定义图像中一个菜单条目的`X，Y`位置和大小。当鼠标在该条目上被释放时产生`message`消息。

## D.3 字体

就象在关于skin的各部分的一节中论及的，字体由一个图像和一个描述文件定义。你能将字符放置在图像中的任何地方， 但是必须确保他们的位置和大小被精确的提交给描述文件。

字体描述文件随着(以`.fnt`为扩展名)能有以'`;`'开始的注释行。文件必须有像这样的行

`image = image`
  其中`image`是用于字体的图像文件的名字(你不必制定扩展名)。
`"char" = X, Y, width, height`
  这里`X`和`Y`指定`char`字符在图像中的位置(`0,0`表示左上 角)。`width`和`height`是字符的尺寸，以象素为单位。

这个例子中用`font.png`定义A，B，C三个字符。

    ; Can be "font" instead of "font.png".
    image = font.png

    ; Three characters are enough for demonstration purposes :-)
    "A" =  0,0, 7,13
    "B" =  7,0, 7,13
    "C" = 14,0, 7,13

### D.3.1 符号

dlabel中使用的一些变量返回的一些字符有特殊的意义。这些字符应该被显示为符号， 使得播放DVD时显示一个漂亮的DVD logo而不是字符‘d’。

下列的表格列出所有能被用来显示符号的字符(所以要求另一种字体)。

字符 | 符号
--- | ---
`p` | 播放
`s` | 停止
`e` | 暂停
`n` | 无声
`m` | 单声道
`t` | 立体声
`f` | 媒体流是文件
`v` | 媒体流是Video CD
`d` | 媒体流是DVD
`u` | 媒体流是URL

## D.4： GUI信息

这些是能被按钮，滑动条和菜单项产生的消息。

注意：一些信息可能不像所预想的那样工作(或者根本不工作)。你也知道，GUI还在开发中。

### Playback控制：

> evNext
>   跳到播放列表中下一个track。
> evPause
>   暂停播放。
> evPauseSwitchToPlay
>   与`evPlaySwitchToPause`一起形成开关。他们能用来实现普通的播放/暂停按钮。两条信息应该被分配到 窗口中同一位置的两个按钮上。这条信息暂停播放并使`evPlaySwitchToPause`按钮的图像显示出来(表明点击按钮能继续播放)。
> evPlay
>   开始播放。
> evPlaySwitchToPause
>   与`evPauseSwitchToPlay`对应的消息。这条信息开始播放并使`evPauseSwitchToPlay` 按钮的图像显示出来(表明点击按钮能暂停播放)。
> evPrev
>   跳到播放列表中上一个track。
> evStop
>   停止播放。

### 搜索：

> evBackward10sec
> evBackward1min
> evBackward10min
>   向后搜索10秒/1分钟/10分钟。
> evForward10sec
> evForward1min
> evForward10min
>   向前搜索10秒/1分钟/10分钟。
> evSetMoviePosition
>   搜索到制定位置(能被滑动条使用；使用与滑动条相关的值( 0-100% ))。

### 视频控制：

> evDoubleSize化
>   把电影窗口置为双倍大小。
> evFullScreen
>   切换全屏方式。
> evNormalSize化
>   把电影窗口置为正常大小。

### 音频控制：

> evDecAudioBufDelay
>   减少音频缓冲延迟。
> evDecBalance
>   减少声道平衡。
> evDecVolume
>   减少音量。
> evIncAudioBufDelay
>   增加音频缓冲延迟。
> evIncBalance
>   增加声道平衡。
> evIncVolume
>   增加音量。
> evMute
>   禁音/取消禁音。
> evSetBalance
>   设置声道平衡(能被滑动条使用；使用与滑动条相关的值( 0-100% ))。
> evSetVolume
>   设置音量(能被滑动条使用；使用与滑动条相关的值( 0-100% ))。

### 其他：

> evAbout
>   打开关于窗口。
> evEqualizer
>   打开/关闭均衡器。
> evExit
>   退出程序。
> evIconify
>   窗口图标化。
> evLoad
>   装载文件(打开一个文件浏览窗口，你能在其中选择文件)。
> evLoadPlay
>   功能与`evLoad`一样，但是它在文件之后装载自动地开始播放。
> evNone
>   空信息，它没有效果(也许CVS版本除外:-))。
> evPlaylist
>   打开/关闭播放列表窗口。
> evPlayDVD
>   尝试打开指定的DVD-ROM驱动器中的碟片。
> evPlayVCD
>   尝试打开指定的CD-ROM驱动器中的碟片。
> evPreferences
>   打开选项设置窗口。
> evSetAspect
>   设置显示图像的屏幕高宽比。
> evSetURL
>   显示URL对话窗口。
> evSkinBrowser
>   打开skin浏览器窗口。