SkinCalc Skinning Tutorial

Copyright 2003, Carmen DiMichele

Updated April 15, 2003

This document holds information on creating skins for SkinCalc. It is in three sections. The first section, is structural information on SkinCalc skins. The second section, is a step-by-step tutorial on how to create a skin. The third section gives details on scripting support and functions structure.

Contents

1 Structural Information
1.1 File structure
1.2 Loading process
1.3 skin.xml
1.4 keys.xml
1.5 scripts.xml
1.6 Buttons
2 Tutorial
2.1 Copy A Current Skin
2.2 Modify skin.xml Basic Information
2.3 Modify background.bmp
2.4 Create a New font.bmp (or use an existing one)
2.5 Update the Display Attributes
2.6 Define a Set of Buttons
2.6.1 Define the Base and Angle Mode Indicators/Buttons
2.6.2 Define a Shift Button
2.6.3 Define The Momentary Buttons
3 Functions
3.1 Embedded Functions
3.2 Script Function Support

1 Structural Information

1.1 File structure

The basic file structure of SkinCalc is as follows:

  SkinCalc
    |--- SkinCalc.exe
    |--- configuration.xml
    |--- skins
           |-- (individual skins folders)
           |--- default (sample skin folder)
                  |--- background.bmp, font.bmp
                  |--- skin.xml, keys.xml, scripts.xml
                  |--- screenshot.jpg
                  |--- buttons
                         |--- buttons.xml
                         |--- bin.bmp, oct.bmp, dec.bmp, hex.bmp
                         |--- rad.bmp, deg.bmp, grd.bmp, cyc.bmp
                         |--- dn.bmp, up.bmp
                         |--- snShift.bmp, upShift.bmp

Each individual skin for SkinCalc is self-contained within its own folder.

1.2 Loading process

SkinCalc locates all folders under the "skins" folder to determine which skins are available for the SkinCalc skin browser (accessed by pressing F2 in SkinCalc).

SkinCalc then uses the skin.xml file of each folder to determine general information about the skin. From this file, each other file for the skin is used to craft the skin you see.

1.3 skin.xml

The following is a sample skin.xml file. This one is from the actual default skin:

  <?xml version="1.0"?>
  <SkinCalcSkin version="2.0">

      <!-- Topmost skin definition file -->

      <name>SkinCalc Default</name>
      <version>1.2</version>
      <author>Carmen DiMichele</author>
      <comment>Basic basic. Updated for SkinCalc v2.</comment>
      <email>shomenuchikomi@netzero.com</email>
      <homepage>skincalc.sourceforge.net</homepage>

      <!-- The screenshot window is 135x235 -->
      <screenshot>screenshot.jpg</screenshot>

      <background background="background.bmp" trans_r="0" trans_g="0" trans_b="255" />
      <display x="24" y="23" cols="26" rows="7" font="font.bmp" chars="0123456789.:E+-ABCDEF" />

      <include file="keys.xml" />
      <include file="scripts.xml" />
      <include file="buttons\buttons.xml" />

  </SkinCalcSkin>

"<?xml version="1.0"?>" identifies skin.xml as a version 1.0 XML file.

"<SkinCalcSkin version="2.0">" identifies skin.xml as a SkinCalcSkin file made in compliance with SkinCalc version 2.0.

"<!-- Topmost skin definition file -->" is a comment.

"<name>SkinCalc Default</name>" depicts the title of the skin.

"<version>1.2</version>" depicts the version of the skin.

"<author>Carmen DiMichele</author>" depicts the author of the skin.

"<comment>Basic basic. Updated for SkinCalc v2.</comment>" is an author comment shown in SkinCalc in information on the skin.

"<email>shomenuchikomi@netzero.com</email>" depicts the e-mail address of the author of the skin.

"<homepage>skincalc.sourceforge.net</homepage>" depicts the homepage of the author.

"<!-- The screenshot window is 135x235 -->" is a comment.

"<screenshot>screenshot.jpg</screenshot>" depicts the filename of a screenshot image of the skin. This image is that shown in the skin browser for the skin and should be 135x235 pixels.

"<background background="background.bmp" trans_r="0" trans_g="0" trans_b="255" />" depicts both the filename of the skin background file and the red, green, and blue components of the color to use as transparent when interpreting the file. In this case, full blue will be rendered as transparent.

"<display x="24" y="23" cols="26" rows="7" font="font.bmp" chars="0123456789.:E+-ABCDEF" />" depicts information about the numeric display. x, y depicts the top, left position of the characters on the display. cols, rows depict the size of the display in characters. font depicts the font bitmap to be used for rendering characters on the display. chars depicts the character string represented in the font bitmap, in order (note: The "" in the chars line above if character 127 (Alt+0127 on the numberpad) and is used to represent and ellipsis character.

"<include file="keys.xml" />" calls out keys.xml to be included as part of this skin.

"<include file="scripts.xml" />" calls out scripts.xml to be included as part of this skin.

"<include file="buttons\buttons.xml" />" calls out buttons.xml in the buttons sub-folder to be included as part of this skin.

"</SkinCalcSkin>" closes skin.xml.

1.4 keys.xml

The following is a sample keys.xml file. This file assigns user keyboard keystrokes to particular SkinCalc functions. These function may be either embedded functions (section 3.1) or those created from a script in scripts.xml (section 1.5). This one is from the actual default skin:

  <?xml version="1.0"?>
  <SkinCalcSkin version="2.0">

    <!-- Keystroke definition file -->
    <key press="^a" action="nextAngle" />
    <key press="^b" action="nextBase" />
    <key press="?" action="about" />
    <key press="n" action="chs" />
    <key press="o" action="cos" />
    <key press="p" action="pi" />
    <key press="s" action="sin" />
    <key press="t" action="tan" />
    <key press="x" action="eex" />

  </SkinCalcSkin>

Note: Keystrokes are not case-sensitive in SkinCalc (i.e., a keystroke of "a" is equivalent to a keystroke of "A").

"<?xml version="1.0"?>" identifies keys.xml as a version 1.0 XML file.

"<SkinCalcSkin version="2.0">" identifies keys.xml as a SkinCalcSkin file made in compliance with SkinCalc version 2.0.

"<!-- Keystroke definition file -->" is a comment.

"<key press="^a" action="nextAngle" />" allows a keystroke of ctrl-A to invoke the nextAngle embedded function (these are written about later).

"<key press="^b" action="nextBase" />" allows a keystroke of ctrl-B to invoke the nextBase embedded function.

"<key press="?" action="about" />" allows a keystroke of "?" to invoke the about embedded function.

You get the picture...

Finally, "</SkinCalcSkin>" closes the file.

1.5 scripts.xml

The following is a sample scripts.xml file. This one is from the actual default skin:

  <?xml version="1.0"?>
  <SkinCalcSkin version="2.0">

    <!-- Scripts used to define functions. -->
    <script action="abs"  	desc="Absolute value"	 script="calc.push(abs(calc.pop()))" />
    <script action="drop" 	desc="Drop"		 		 script="calc.pop()" />

    <script action="+"	  	desc="Add"				 script="calc.push(calc.pop() + calc.pop())" />
    <script action="-"	  	desc="Subtract"			 script="x = calc.pop(): calc.push(calc.pop() - x)" />
    <script action="*"	  	desc="Multiply"			 script="calc.push(calc.pop() * calc.pop())" />
    <script action="/"	  	desc="Divide"			 script="x = calc.pop(): calc.push(calc.pop() / x)" />

    <script action="sin"  	desc="Sine"				 script="calc.push(sin(calc.A2R(calc.pop())))" />
    <script action="asin" 	desc="Arcsine"			 script="x = calc.pop(): calc.push(calc.R2A(Atn(x/Sqr(-x*x+1))))" />
    <script action="cos"  	desc="Cosine"			 script="calc.push(cos(calc.A2R(calc.pop())))" />
    <script action="acos" 	desc="Arccosine"		 script="x = calc.pop(): calc.push(calc.R2A(Atn(-x/Sqr(-x*x+1))+2*Atn(1)))" />
    <script action="tan"  	desc="Tangent"			 script="calc.push(tan(calc.A2R(calc.pop())))" />
    <script action="atan" 	desc="Arctangent"		 script="calc.push(calc.R2A(Atn(calc.pop())))" />

    <script action="sigma"	desc="Sigma (sum stack)" script="x = 0: while calc.stackCount: x = x + calc.pop(): wend: calc.push(x)" />
    <script action="pi"		desc="Pi"				 script="calc.push(calc.pi)" />

  </SkinCalcSkin>

The first three lines do the same as for the previous two .xml files.

"<script action="abs" desc="Absolute value" script="calc.push(abs(calc.pop()))" />" defines a function with and ID of "abs". This function is described by the term "Absolute value" and operates by executing the script "calc.push(abs(calc.pop()))" when invoked (more on scripts later).

You can probably guess how the rest works.

1.6 Buttons

The buttons folder and all files within it define the look and functional connections of SkinCalc's buttons. As you may guess, this all starts with the buttons.xml file. Of which, here is the one from the default skin:

  <?xml version="1.0"?>
  <SkinCalcSkin version="2.0">

    <!--  buttons.xml defines the layout of the SkinCalc buttons --> 

    <!--  Special function buttons. Those not definable from the up and down bitmaps. Base button, angle button, etc. -->
    <base	x="188"	y="133"	binImage="bin.bmp"	octImage="oct.bmp"	decImage="dec.bmp"	hexImage="hex.bmp"	tooltip="Binary/Octal/Decimal/Hexadecimal Base"			/>
    <angle	x="218"	y="133"	degImage="deg.bmp"	radImage="rad.bmp"	gradImage="grd.bmp"	cycImage="cyc.bmp"	tooltip="Degrees/Radians/Gradians/Cycles Angle Mode"	/>
    <shift	x="16"	y="168"	image="upShift.bmp"	downImage="dnShift.bmp"										tooltip="Shift"		   									/>

    <!-- Momentary buttons. Those definable from the up and down bitmaps. -->
    <momentary image="up.bmp" downImage="dn.bmp">

      <!--  Special cases (odd sizes or not part of an array) --> 
      <button	action="off"		x="16"	y="133"	width="34" height="32" /> 
      <button action="tray"		x="215"	y="2"	width="23" height="12" />
      <button	action="enter/edit"	x="133"	y="317"	width="34" height="69" />

      <!--  Hexadecimal Entry Array -->	
      <array x0="16" y0="206" xSpacing="39" ySpacing="0" width="34" height="32">
        <button	action="A/fix" />
        <button	action="B/sci" />
        <button	action="C/free"	/>
        <button	action="D" />
        <button	action="E" />
        <button	action="F" />
      </array>

      <!--  Numeric Pad --> 
      <array x0="16" y0="243" xSpacing="0" ySpacing="37" width="34" height="32">
        <button	action="7" /> 
        <button	action="4" /> 
        <button	action="1" /> 
        <button	action="0" /> 
      </array>

      <array x0="55" y0="243" xSpacing="0" ySpacing="37" width="34" height="32">
        <button	action="8" /> 
        <button	action="5" /> 
        <button	action="2" /> 
        <button	action="." />
      </array>

      <array x0="94" y0="243" xSpacing="0" ySpacing="37" width="34" height="32">
        <button	action="9" /> 
        <button	action="6" /> 
        <button	action="3" /> 
        <button	action="chs" />
      </array>

      <!--  Editing array -->
      <array x0="133" y0="243" xSpacing="0" ySpacing="37" width="34" height="32">
        <button	action="eex/abs" />
        <button	action="back/drop" />
      </array>
		
      <!--  Arithmetic Column -->
      <array x0="172" y0="243" xSpacing="0" ySpacing="37" width="34" height="32">
        <button	action="/" /> 
        <button	action="*" /> 
        <button	action="-" /> 
        <button	action="+" /> 
      </array>

      <!--  Trigonometry Column -->	
      <array x0="211" y0="243" xSpacing="0" ySpacing="37" width="34" height="32">
        <button	action="sin/asin" />
        <button	action="cos/acos" />
        <button	action="tan/atan" />
        <button	action="pi/sigma" />
      </array>

    </momentary>

  </SkinCalcSkin>

The "base" element has attributes: x, y, binImage, octImage, decImage, hexImage, and tooltip. This element defines where (x, y) the base selection button is, what it looks like in each state (binary, octal, decimal, and hexadecimal), and what to show as a tooltip when the user hovers the mouse over it.

The "angle" element does the same for the angle mode selection button (radians, gradians, degrees, and cycles).

The "shift" button is a two-state button and is definable using only two images (up and down).

The of SkinCalc's buttons are "momentary" buttons. This means they do not hold a state once released. They reset to the up position when released. The "momentary" element defines all of these buttons. It's attributes of "image" and "downImage" give a composite of the up and down states of each of these buttons. This is more convenient than adding two bitmaps for each button individually.

Within the "momentary" element, there are "button" elements. Note all "buttons" elements have an "action" attribute. This tells SkinCalc what function to invoke when the particular button is pressed by the user. When an action is defined with a "/", as in the case of the third button, "enter/edit", it defines invoking the "enter" function when the button is pressed and the "edit" function being invoked when the button is pressed in a shift condition.

The first type of "button" elements shown, non-array, have attributes x, y, width, and height in addition to action. This tells SkinCalc where and how big in the "image" and "downImage" composite bitmaps the skin for the particular button is.

Button arrays can be made. These are only intended to simplify the process. All buttons can be made using the non-array variety. In an "array" element, the attributes x0, y0 define the top, left of the array. xSpacing, ySpacing define the offset of each successive button and width, height define the size of each button. Then within the "array" element, each button is defined in order of the array.


2 Tutorial

2.1 Copy A Current Skin

To start, copy an already created skin. In this case, make a copy of the "default" folder and all its contents to a new folder. Rename the new folder to "oneline". This will be our new skin and we will be working only within this folder.

2.2 Modify skin.xml Basic Information

Open "skin.xml" in a text editor like Notepad or similar. Change the skin information to reflect our new skin:

  <name>One-Line Calculator
  <version>1.0
  <author>Carmen DiMichele
  <comment>I was thinking of the good old HP-11.
  <email>shomenuchikomi@netzero.com
  <homepage>skincalc.sourceforge.net

2.3 Modify background.bmp

Open "background.bmp" in your favorite graphics editor. Modify the bitmap to be the new skin's background. The skin background has the following function aspects:

  1. The basic background of the skin itself.
  2. The background of the display area where characters will be rendered.
  3. Transparent areas where the desktop will show through the skin.

In this example, I have changed the original background.bmp:

To this:

Notice, in both images there is a display area and blue transparent areas (very small corners in the new background). If blue is an integral part of our background image that we do not want to be transparent, we may change the transparency color to anything we want. We do this by changing the "background" element's "trans_r", "trans_g", and "trans_b" attributes to reflect our desired transparent color. For instance, if we want SkinCalc to render full white parts of background.bmp as transparent, we would change skin.xml to state:

  <background background="background.bmp" trans_r="255" trans_g="255" trans_b="255" />

2.4 Create a New font.bmp (or use an existing one)

"font.bmp" is used to render SkinCalc's text onthe skin's display area. If appropriate, you can just copy a "font.bmp" to fit a new skin. However, if a new one needs to be created for a different appearance, here's how it can be done.

In your favorite graphics editor create "font.bmp". In this example, I created this one to go with the One-Line Calculator skin:

It is the full set of characters required by SkinCalc in the same order as depicted in the "chars" attribute of the skin.xml line:

  <display x="24" y="23" cols="26" rows="7" font="font.bmp" chars="0123456789.:E+-ABCDEF" />

Notice also all charcters in "font.bmp" are fixed spaced. This is required by SkinCalc.

2.5 Update the Display Attributes

For the new font and background to operate properly, we need to set the display attributes appropriately. Doing a test with the new font on the new background, I see that I want the top, left of the display to be at: 14,20 (the top-most, left-most corner of the first "0" of the font on the display):

I also see that my new display is 27 columns by one row. Therefore, I change the "display" element attributes in "skin.xml" as follows:

  <display x="14" y="20" cols="27" rows="1" font="font.bmp" chars="0123456789.:E+-ABCDEF" />

2.6 Define a Set of Buttons

The basic flow of this process can be as follows:

  1. Create a "base" mode indicator/button.
  2. Create a "angle" mode indicator/button.
  3. Create a "shift" button.
  4. Create all the rest of the buttons in two files, "up.bmp" and "dn.bmp".

2.6.1 Define the Base and Angle Mode Indicators/Buttons

Oneline's base and angle indicators/buttons will look like this:

To create the base indicator/button we need four bitmaps: "bin.bmp", "oct.bmp", "dec.bmp", and "hex.bmp" to cover all four base modes (er, cover all four bases ;-). I create the four .bmp files and modify the "base" element of the "buttons.xml" file for the indicator/button's new location, 234,34:

  <base x="234" y="34" binImage="bin.bmp" octImage="oct.bmp" decImage="dec.bmp" hexImage="hex.bmp" tooltip="Binary/Octal/Decimal/Hexadecimal Base" />

Similarly, the new angle indicator/button takes four bitmaps: "deg.bmp", "rad.bmp", "grd.bmp", and "cyc.bmp". It now hase the origin coordinates of 199,34. So, the "angle" element now reads:

  <angle x="199" y="34" degImage="deg.bmp" radImage="rad.bmp" gradImage="grd.bmp" cycImage="cyc.bmp" tooltip="Degrees/Radians/Gradians/Cycles Angle Mode" />

2.6.2 Define a Shift Button

The shift button is defined similarly to the base and angle mode buttons. However, it is a little simpler. The shift button has only two states, on and off, or, down and up, respectively. The following is the new "shift" element for "buttons.xml". With the new bitmaps in place in the buttons folder, the only thing to change is the origin coordinates to 109,183:

 
  <shift x="109" y="183" image="upShift.bmp" downImage="dnShift.bmp" tooltip="Shift" />

2.6.3 Define The Momentary Buttons

Yeah! Only two more bitmaps to go for the buttons folder to be complete. "up.bmp" and "dn.bmp" from the following line in "buttons.xml" defines the composite up and down images of all the momentary buttons in only two bitmaps:

  <momentary image="up.bmp" downImage="dn.bmp">

Notice, this line does not end with a "/". This means that as an element, it is not complete here. The "momentary" element will be fully defined when the following line toward the end of the file is reached:

  </momentary>

So, all buttons defined between these two lines will have their images clipped out of "up.bmp" and "dn.bmp".

Two types of button definitions can exist within the "momentary" element block. A single button may be defined as the "off" button is defined below:

  <button action="off" x="16" y="133" width="34" height="32" />

Note, the height and width of the button must be given here since its images will be clipped from larger bitmaps.

Note also the other differences between this type of definition and that of the previous base, angle, and shift definitions. Here, we will define an "action" that this button will take on. Because of this, a "tooltip" need not be given. It will be defined either as part of the embedded functions or as part of the scripted function being called by this button.

Under Construction


3. Functions

3.1 Embedded Functions

The following lists the embedded functions of SkinCalc. Each is assignable to a keystroke or button action in keys.xml or buttons.xml respectively:

offSwitch SkinCalc off/exit SkinCalc.
0 thru 9, A thru F, .Numeric entry.
enterEnter the prompt/editing line into the stack.
backBackspace while editing or drop top stack entry when not.
chsChange sign. During editing either change the sign of the entire entry or it's exponent if in exponent entry mode. If not in editing mode, change sign of top stack entry.
eexEnter exponent.
fixChange to fixed notation mode (i.e., 1234.003). This function uses one value to determine how many decimal places to fix display to.
sciChange to scientific notation mode (i.e., 1.234E+003). This function uses one value to determine how many decimal places to fix display to.
freeChange to free notation mode. No values are used in this function. This mode will display values without fixing its decimal places nor necessarily displaying with an exponent.
editBrings the top stack item down to the prompt/editing line for editing.
aboutOpens the SkinCalc about box.
skinsOpens the SkinCalc skin browser.
nextBaseSelects the next numeric base mode.
nextAngleSelects the next angle mode.
traySends SkinCalc to the desktop icon tray.
decSelect decimal numeric base mode.
hexSelect hexadecimal numeric base mode.
binSelect binary numeric base mode.
octSelect octal numeric base mode.
degSelect degrees angular base mode.
radSelect radians angular base mode.
grdSelect gradients angular base mode.
cycSelect cycles angular base mode.

3.2 Script Function Support

The following lists the functions supported as an interface between the VBScript feature of SkinCalc and the application itself. A script function is defined in scripts.xml and assigned to a key and/or button action in keys.xml and/or buttons.xml respectively:

calc.pi() as doubleReturns the value of Pi the constant.
calc.peek(index as integer) as doubleReturns the stack value designated by 'index'.
calc.poke(index as integer, x as double)Changes the stack value designated by 'index' to 'x'.
calc.pop() as doubleReturns the top stack value and pops it from the stack.
calc.push(x as double)Pushes 'x' onto the stack.
calc.stackCount() as integerReturns the number of items currently in the stack.
calc.R2A(x as double) as doubleReturns 'x' converted from radians to the current angular base.
calc.A2R(x as double) as doubleReturns 'x' converted from the current angular base to radians.

From scripts.xml:

  <script action="inv" desc="Inverse" script="calc.push(1/calc.pop())" />

This defines a new action "inv" which is described as "Inverse" and will replace the top stack value with its arithmetic inverse: x = 1/x.

The next step is to attach it to buttons and/or keys. In this case it is attached to one button. This is done by buttons.xml:

  ...
  <array x0="108" y0="111" xSpacing="30" ySpacing="0" width="27" height="23">
    <button action="inv" />
  ...

From here, you may want to look closer at scripts.xml to see how they work or take a look at VBScript documentation here.