Open main menu

GUI Themes/Specs

< GUI Themes
Revision as of 01:32, 4 February 2007 by LordHoto (talk | contribs) (→‎Examples: merged the two example tables)

See GUI TODO. See here for theme downloads.

GUI Themes config file format

Overview

We always have a built-in theme. It is used when there is no external .ini file. For simplicity it uses exactly same format as external .ini but is defined in Theme::_defaultConfigINI string in gui/theme-config.cpp file.

Config file consists of at least one section. These sections can override one another. This is used to make a slight alteration of base theme possible without duplicating all element whose position is not changed.

NOTE: if you want to add new widgets, pay attention to correspondent section below

Section names

They are defined with this regexp: (X|[0-9]+)x(Y|[0-9+]+). I.e. possible names are:

  • [XxY] -- universal one which can be used for any resolution
  • [640xY] -- could be used for 640x400 and 640x480
  • [Xx400] -- could be used for 640x400 only (or any other resolution with height 400)
  • [640x480] -- could be used for 640x480 only

Expressions

To add most flexibility arbitrary arithmetic expressions can be used for specifying any element. Allowed operations are '(', ')', '+', '-', '*', '/'. unary '+' and unary '-'. Atoms are either number or symbolic names.

Built-in Constants

Currently there are these built-in constants defined:

  • kButtonWidth
  • kButtonHeight
  • kSliderWidth
  • kSliderHeight
  • kBigButtonWidth
  • kBigButtonHeight
  • kBigSliderWidth
  • kBigSliderHeight
  • kTextAlignLeft
  • kTextAlignCenter
  • kTextAlignRight
  • kFontStyleBold
  • kFontStyleNormal
  • kFontStyleItalic
  • kFontStyleFixedBold
  • kFontStyleFixedNormal
  • kFontStyleFixedItalic

These correspond to constants defined in gui/widget.h file. There is no restriction on constants names.

  • kThumbnailWidth -- defined in graphics/scaler.h
  • false = 0
  • true = 1

Built-in Variables

Built-in variables are symbolic names for ScummVM variables whose value is determined at run-time. These are:

  • w -- current GUI width
  • h -- current GUI height

Defining widget positions

Widgets are specified by following construction:

 widget_name=X Y [W H]

X, Y, W and H are whitespace-delimited expressions. W and H are optional.

This construct effectively defines

  • widget_name.x
  • widget_name.y
  • widget_name.w
  • widget_name.h

If W and H are present, also these get defined:

  • widget_name.x2 = widget_name.x + widget_name.w
  • widget_name.y2 = widget_name.y + widget_name.h

Example:

 chooser_headline=10 6 (w - 2 * 16) (kLineHeight)

Widget properties

Above mentioned constructions with dots are called widget properties.

Example:

 chooser_list.x

Also there are following additional widget properties:

  • .visible -- if set to 0, then widget is not drawn
  • .align -- for text widgets defines text alignment (kTextAlignLeft, kTextAlignRight or kTextAlignCenter). Default is kTextAlignLeft

Widget class properties

Each widget class can be customized per-resolution. You need to specify their special properties.

ListWidget

This is widget with list of selectable items

ListWidget.leftPadding=7                                                       
ListWidget.rightPadding=7                                                      
ListWidget.topPadding=5                                                        
ListWidget.bottomPadding=5                                                     
ListWidget.hlLeftPadding=0                                                     
ListWidget.hlRightPadding=0                                                    

leftPadding, rightPadding, topPadding and bottomPadding specify list contents (text) padding from widget edges. Default values are 0.

hlLeftPadding, hlRightPadding specify padding of selected text highlight, i.e. green bar in modern theme. Default values are 0.

PopUpWidget

This is drop-down list used to select one item out of several. In inactive state it displays only selected item.

PopUpWidget.leftPadding=7                                                      
PopUpWidget.rightPadding=5
PopUpWidget.labelSpacing=3

leftPadding and rightPadding specify list contents (text) padding from widget endges. Default values are 0.

labelSpacing is used to specify space between text label and widget itself.

EditTextWidget

This is editable text.

EditTextWidget.leftPadding=7                                                      
EditTextWidget.rightPadding=5
EditTextWidget.font=kFontStyleNormal 

leftPadding and rightPadding specify list contents (text) padding from widget endges. Default values are 0.

font is used to specify font used by the widget.

Console

This is our debug console

Console.font=kFontStyleFixedNormal
Console.leftPadding=7
Console.rightPadding=5
Console.topPadding=5
Console.bottomPadding=5

font is used to specify font for console. Note, that console uses fixed font.

leftPadding, rightPadding, topPadding and bottomPadding specify console contents (text) padding from widget edges. Default values are 0.


Special variables

Special variables are:

  • self
  • prev

It is reference to current and last defined widget special variables respectively, i.e. .x, .y, .w and .h

Example:

 chooser_list=10 (6 + kLineHeight + 2) (w - 2 * 16) (h - self.y - buttonHeight - 12)

Denote self.y which equals to computed value of (6 + kLineHeight + 2).

You cannot use these references forward, i.e. refer to .w in .x. They get defined from left to right.

Defining variables

Example:

  def_kLineHeight=16 * 2
  OneThirdWidth=(w / 3)

variable kLineHeight gets value 32. OneThirdWidth will be GUI width divided by 3. Note use of parens in last example. Definitions with 'def_' prefix have a special meaning and get skipped with USE keyword (see below).

Defining aliases

You can define alias to any symbolic atom, i.e. constants, variables and widget properties.

Example:

 set_headerBottomX=headline.x2

Now you can use headerBottomX everywhere.

Special alias

 set_parent=chooser_list

It sets 6 aliases for each widget property, i.e.

  • parent.x = chooser_list.x
  • parent.y = chooser_list.y

etc for .w, .h, .x2 and .y2

Example:

 set_parent=tabMidi
 midi_checkbox=(parent.x + 10) (parent.y + 20)
 roland_checkbox=midi_checkbox.x (parent.y + 50)

USE keyword

You can request loading of some particular section at any time within another section. But all variable definitions with def_ prefix get skipped. If you want to define a variable, use plain VAR=VAL construction.

Example:

 [640xY]
 def_buttonHeight=kBigButtonHeight
 def_kLineHeight=16
 listW=(w - 2 * 16)
 chooser_headline=10 6 listW (kLineHeight)
 chooser_list=10 (6 + kLineHeight + 2) listW (h - self.y - buttonHeight - 12)
 
 [320xY]
 def_buttonHeight=kButtonHeight
 def_kLineHeight=9
 use=640xY

In this example for 320xY resolution chooser_headline and chooser_list will be loaded from [640xY] section, though buttonHeight and kLineHeight will be different. listW will get the value.

USEASIS keyword

Same as USE keyword above but without def_ valuse skipped. Used for weird resolution aliases.

Example:

 # MM NES resolution
 [256x240]
 useAsIs=320xY

USEWITHPREFIX keyword

This keyword is similiar to above described USE keyword. The difference is that all defined widgetset will get specified prefix. Example:

 [XxY]
 yoffset=10
 useWithPrefix=audioControls global_
 yoffset=50
 useWithPrefix=audioControls game_
 
 [audioControls]
 myx=10
 myw=(options_dialog.w - 20)
 midipopup=(myx -5) yoffset (myw + 5)

Here you will get global_midipopup and game_midipopup widgets defined.

skipFor keyword

If this key is defined within section, then section loading will be skipped for specified resolutions. For example, it is used in our modern theme to make 320xY widgets be positioned like in our classic theme.

 [XxY]
 skipFor=320xY,256x240
 def_blah=22

In above case section [XxY] will not be loaded for 320x200, 320x240 or 256x240 resolutions. No spaces are allowed in specified value, only [0-9XxYx,]

Modern Theme configuration

'pixmaps' section

In the 'pixmaps' section all pixmaps used by the renderer are defined.

Basically there are four pixmaps per widget/dialog type:

  • "pix_typename_corner" defines the pixmap used for rendering all the corners.The pixmap should show the upper left corner and is x/y flipped if needed.
  • "pix_typename_top" defines the pixmap used for the top/bottom border. The pixmap should show the top border and is y flipped if it draws the bottom border.
  • "pix_typename_left" defines the pixmap used for the left/right border. The pixmap should show the left border and is x flipped if it draws the right border.
  • "pix_typename_bkgd" defines the pixmap used for the background.

Here's some example to defined the pixmaps used for dialog drawing:

pix_dialog_corner="dialog_bkgd_corner.bmp"
pix_dialog_top="dialog_bkgd_top.bmp"
pix_dialog_left="dialog_bkgd_left.bmp"
pix_dialog_bkgd="dialog_bkgd.bmp"

If you want to find out about all definable pixmaps look at our default theme config file, named "modern.ini". Also note that only .bmp files with a bpp of 24 bits are supported. The transparency color used is defined in the 'colors' section (see later on).

Apart from the widget pixmaps definitions in the 'pixmaps' section there are some special pixmaps defined:

  • "pix_widget_arrow" defines the pixmap used for all arrows in widgets (like in the scrollbar widget). It should be an image of an arrow pointing upwards, and is y flipped if an arrow pointing downwards is drawn.
  • "pix_checkbox_empty" defines the pixmap used for empty checkboxes.
  • "pix_checkbox_checked" defines the pixmap used for checked checkboxes.
  • "pix_theme_logo" defines the pixmap used as logo.
  • "pix_cursor_image" defines the pixmap used as mouse cursor. Note that just the first 255 colors found are used.

'colors' section

In the "colors" section colors for the whole theme are specified. A color gets defined in this way:

name=R G B

with values from 0 to 255 for R, G and B.


There is a special color entry to define the transparent color for the pixmaps, named "color_transparency". Our default theme uses pink (255 0 255) as the transparent color.

color_transparency=255 0 255


To set up text colors the following entries have to be set:

color_state_disabled=192 192 192
color_state_highlight=100 162 8
color_state_enabled=0 0 0
  • "color_state_disabled" is used for disabled text.
  • "color_state_highlight" is used for highlighted text.
  • "color_state_enabled" is used for normal text.

The ListWidget uses two special text color entries:

text_inverted_background=100 162 8
text_inverted_color=0 0 0

There "text_inverted_background" is used for the rect which is drawn when an entry is selected, "text_inverted_color" is used for the text drawn when an entry is selected.


Another special color is used for all kinds of text input widgets:

caret_color=0 0 0

This value is used for the color the caret is drawn in.


Some colors are used for background fades, you can easily spot them since they have a '_start' and '_end' suffix. Another example:

main_dialog_start=210 114 10
main_dialog_end=239 196 24

This defines the color fade for the launcher background. "main_dialog_start" defines the color at the top of the drawn area, "main_dialog_end" at the bottom of the drawn area, the colors in between are calculated. (see 'gradients' section for more information).


Sometimes there is more than one color fade definition for a widget, the button widget uses for example one colorfade for normal drawing and a special fade for highlighted drawing. Example:

button_bkgd_start=203 126 107
button_bkgd_end=169 42 12
button_bkgd_highlight_start=255 210 200
button_bkgd_highlight_end=200 70 50
  • "button_bkgd_start" and "button_bkgd_end" are used for normal drawing.
  • "button_bkgd_highlight_start" and "button_bkgd_highlight_end" are used for highlighted drawing.


There are three special entries for the button widget to define the text color:

button_text_enabled=255 255 255
button_text_disabled=192 192 192
button_text_highlight=255 214 84
  • "button_text_enabled" is used for normal buttons.
  • "button_text_disabled" is used for buttons which are currently disabled.
  • "button_text_highlight" is used for highlighted buttons.

If you want to find out all defineable colors look at our default theme config file, named "modern.ini".

'gradients' section

In the 'gradients' section the gradient factors for the different widget/dialog types are defined.

Some example define:

gradient_dialog_main=1

Which is for the background of the launcher dialog. If you want to find out about all definable gradients look at our default theme config file, named "modern.ini".

To see what this value does here's how the calculate the color of a row in a widget/dialog:

calcGradient(firstLineColor, lastLineColor, currentLine, maxLineNumber, factor)
      currentLine = currentLine * factor

      if currentLine >= maxLineNumber then
         return lastLineColor

      return firstLineColor + (lastLineColor - firstLineColor) * currentLine / maxLineNumber

As you can see we're using a linear interpolation here. Since it's pseudocode it's a bit simplified though, but it should be enough to get the basic idea.

Examples

To have some examples showing in how far a different factor value changes the colors here are coming two.

The color values we use in our examples:

firstLineColor=210 114 10
lastLineColor=239 196 24

The following shows the difference between a factor value of 1 and 2 over 10 lines:

Factor 1 Factor 2
line0=210 114 10 line0=210 114 10
line1=213 123 11 line1=216 132 13
line2=216 132 13 line2=222 150 16
line3=219 141 14 line3=229 168 19
line4=222 150 16 line4=235 186 22
line5=226 159 17 line5=239 196 24
line6=229 168 19 line6=239 196 24
line7=232 177 20 line7=239 196 24
line8=235 186 22 line8=239 196 24
line9=239 196 24 line9=239 196 24

'extra' section

Shadows

Shadows are defined in number of extra pixels at each side. However, each widget uses its own shadow format. Currently it is hardcoded, but if there is a need, it could be easily added to the theme config.

 [extra]
 shadow_left_width=2
 shadow_right_width=4
 shadow_top_height=2
 shadow_bottom_height=4

Specifies number of extra pixels which shadow covers. This is right-bottom shadow.

Fonts

Fonts used in the theme could also be specified. You should provide the font file in BDF format and put it to the theme archive.

 [extra]
 fontfile_normal="helvr12-l1.bdf"
 fontfile_bold="helvb12-l1,bdf"
 fontfile_italic="helvi12-l1.bdf"
 fontfile_fixed_normal="courr12-l1.bdf"
 fontfile_fixed_bold="courb12-l1.bdf"
 fontfile_fixed_italic="couri12-l1.bdf"

Specifies fonts for Variable Normal, Bold and Italic weight, as well as fixed width fonts.

At first load ScummVM will load BDF fonts which are in slow ASCII format and will write binary precompiled versions to files with extencion 'FCC'. You may consider putting these files to theme ZIP file if you will want to distribute your theme.

Inactive dialog effects

For using an effect change the "inactive_dialog_shading" option in the "[extra]" section of default-theme.ini. Possible values are: "no_effect", "luminance" and "dim". (Note that currently backends which don't copy the game screen into the overlay buffer should use "no_effect").

  • "luminance" will change all inactive screen areas to black and white.
    • Example (enables it)
 [extra]
 inactive_dialog_shading=luminance
  • "dim" will dim the screen with the given percentage value.
    • "shading_dim_percent" in the "[extra]" section sets the dimming value. 0 means no dim, 100 is completeley black
    • Example (30% screen dim):
 [extra]
 inactive_dialog_shading=dim
 shading_dim_percent=30
Cursor parameters

Cursors are specified in cursor pixmap (see pixmpas section). Section extra specifies several additional parameters:

 [extra]
 cursor_hotspot_x=0
 cursor_hotspot_y=0
 cursor_targetScale=3

First two parameters define position of cursor hotspot within cursor pixmap (top left corner is [0,0]).

targetScale is used to specify at which scale cursor starts to be scaled. I.e. if targetScale = 2, then cursor will not be scaled at 320xY, but will be scaled 1.5x for 960xY resolution (by factor of [currentScale / cursorTargetScale]. With targetScale = 3 it will not be scaled even at 3x.

It is used when your cursor is designed, say, for 640x480, and original interpretator always scaled 320x200 game graphics.

Evaluation precedence

Within one section everything is computed left to right, down to top. No forward references are allowed. The only exception are aliases which can refer to not yet defined variables and widget properties, but at time of useage those variables should be defined (otherwise you will get an error).

Currently any error in evaluation will lead to error() and ScummVM will be closed. So be careful, especially with the built-in theme.

On each resolution change all user-defined variables and aliases get cleared and all sections are recomputed. When sections get loaded for a single resolution, all of them are kept, so you can specify a generic [XxY] scheme and then overwrite only some widgets, thus simplifying the whole thing.

Sections loading order is always the same. For the 640x480 resolution this is:

  1. Built-in theme
    1. [XxY]
    2. [640xY]
    3. [Xx480]
    4. [640x480]
  2. Custom theme
    1. [XxY]
    2. [640xY]
    3. [Xx480]
    4. [640x480]

Only present sections are loaded. If a section is not defined no error message is generated.

Widget name conventions

Widget names are given in the following form:

 dialog_widget

where dialog_ is the dialog name, and widget is a distinguishable name within that dialog. Be discreet and give meaningful names.

Example:

 chooser_headline
 chooser_list

What to do if I need to add new widgets to GUI

Most importantly, not all GUI behaviour is described in theme config. You can only alter the look, not the feel. So all real coding should go into the corresponding files in the gui/ directory.

When you add a new widget, follow this checklist before committing:

  • Does it look right in 320xY (./scummvm --force-1x-overlay)
    • To do this you should either have no absolute positions in your config file or create [320xY] section
  • Does it look right with classic theme (./scummvm --gui-theme=classic)
    • that is the [XxY] section in gui/theme-config.cpp
  • Does it look right both with classic theme and 320xY resolution (./scummvm --force-1x-overlay --gui-theme=classic)
    • that is the [320xY] section in gui/theme-config.cpp

Currently the classic theme has the following most notable differences from the modern theme:

  • Line spacing is narrower everywhere
  • Indentation is smaller in most cases apart from the Game Options dialog