# Defining functions in stylesheets

Is there a way to define functions in a stylesheet? So far I have managed to write my stylesheets without the need to use my own custom functions or definitions. For instance, maybe I have some color that I wish to use throughout my stylesheet.

myColor = RGBColor[.5,.5,.5];


The reason I would like to do this is that later on, if I change the color, every style that depends myColor will automatically change. This can apply to other functions that you might create. I know that I can use any built-in function I want in the stylesheets. Is there a way to define custom functions to use in a stylesheet without making a package?

If making a package is the only way, how can we make sure the stylesheets that use such package load the package first so that the styles are properly defined?

-
No, I don't think you can do that. You can't even use variables (e.g. named colours such as Blue) in stylesheets –  The Toad Jul 1 '12 at 2:10
Darn, I like the fact that we can use Red and other defined colors or functions in the stylesheets. Too bad we can't define our own. Or can ... ALL GLORY TO THE HYPNOTOAD!!! –  jmlopez Jul 1 '12 at 2:13
I don't think you can use Red or any other named colour (AFAIK). See the difference by adding Cell[StyleData["Input"], Background -> RGBColor[1,0,0]] and Cell[StyleData["Input"], Background -> Red] (one at a time) to the stylesheet –  The Toad Jul 1 '12 at 2:17
@RM, yeah, just did, I better go eat something. So how come we can use RGBColor[1,0,0] but not Red. What are the limits of built-in expressions we can use in the making of stylesheets? –  jmlopez Jul 1 '12 at 2:23
That's a good question and I don't really know the answer... The way I interpret it (possibly incorrect) is that the stylesheet can understand any command/directive that doesn't require the use of the kernel to interpret it. In this framework, RGBColor[r,g,b] can be interpreted simply by parsing the expression, whereas Blue requires it to be evaluated or its OwnValues read to get the rgb values. –  The Toad Jul 1 '12 at 2:55

This is my suggestion: use CurrentValue and TaggingRules in this way:

1) Create a notebook in the stylesheet lookup path, say "myStyleParameters.nb", where you'll store your parameters. Add a cell such as

Cell[StyleData["Notebook"], TaggingRules->{"color"->GrayLevel[0.5], "height"->222}];


2) Open your custom stylesheet, say "myStyle.nb", then go to Format->Edit stylesheet to edit the stylesheet's style, and prepend a cell similar to the only one you have there, but inheriting from "myStyleParameters.nb"

Cell[StyleData[StyleDefinitions->"myStyleParameters.nb"]


3) Go to your stylesheet "myStyle.nb" and prepend that same cell

4) Use, wherever you like that color, CurrentValue[{TaggingRules, "color"}]. E.g

Cell[StyleData["testStyle"], Background->CurrentValue[{TaggingRules, "color"}]

-
Could you point out how to attach the TaggingRules to the custom stylesheet? All I want is to create a stylesheet so that when a user installs it everything works the way it should. –  jmlopez Jul 1 '12 at 15:54
I just tried it and it seems to work. The only concern I have now is that I get: The specified setting for the option Background cannot be used. in the Messages window when I use that option for the background. It works fine though :), Now, if you just show me where I can put these tagging rules in the stylesheet notebook I'll be able to define a theme of colors to use throughout the notebook. –  jmlopez Jul 1 '12 at 16:00
The answer to my question in the comments: Cell[StyleData["Notebook"], TaggingRules->{"myGreen"->RGBColor[0,.1,0]}]. The only thing that keeps bothering me is the messages that I get when I change the expressions using CurrentValue. Other than that, I believe you have answered the question. Gracias! –  jmlopez Jul 1 '12 at 16:17
@jmlopez, I'm on it. It seems it is not as simple as I thought. Attaching the rules is simple, but making the CurrentValue refer to the style notebook and not to the notebook you're using is not so straightforward for me. –  Rojo Jul 1 '12 at 16:20
However, I'm seing fun things while investigating, such as the background of some cell style changing colors while I switch the input notebook from one to the other, hehe –  Rojo Jul 1 '12 at 16:21

Functions can be used in stylesheets but not defined as per:

myColor = RGBColor[.5,.5,.5];


The reason you cannot, for example, enter Red in a stylesheet is because it is typically written in the underlying box code. By analogy you cannot choose show expression and replace RGBColor[1.,0.,0.] in the underlying expression with Red.

But as @Mr.Wizard said this can be done programatically. For example you can manipulate your current notebooks stylesheet with this sort of code:

SetOptions[EvaluationNotebook[],
StyleDefinitions -> Notebook[
{Cell[StyleData[StyleDefinitions -> "Default.nb"]],
Cell[StyleData["Input"], FontColor -> myColor]},
StyleDefinitions -> "PrivateStylesheetFormatting.nb"
]
]


...in which you can enter a named color. You can change the stylesheet dynamically:

Manipulate[
(SetOptions[EvaluationNotebook[],
StyleDefinitions -> Notebook[
{Cell[StyleData[StyleDefinitions -> "Default.nb"]],
Cell[StyleData["Input"], FontColor -> myColor]},
StyleDefinitions -> "PrivateStylesheetFormatting.nb"
]
];
Style["Input Colour", 18, myColor]),

{myColor, Red}
]


By combining code for "Input", comments, strings and so on you can dynamically compare combinations of font and background colours to create a stylesheet that you personally find aesthetically pleasing.

(* a comment *)
Manipulate[
(SetOptions[EvaluationNotebook[],
StyleDefinitions -> Notebook[
{Cell[StyleData[StyleDefinitions -> "Default.nb"]],
Cell[StyleData["Input"],
Background -> background,
FontSize -> size,
FontColor -> myColor,
AutoStyleOptions -> {
"CommentStyle" -> {FontColor -> commentcolor, FontSize -> 11,
FontFamily -> "Comic Sans MS", ShowAutoStyles -> False,
ShowSyntaxStyles -> False, AutoNumberFormatting -> False},
"StringStyle" -> {FontColor -> stringcolor, FontSize -> 11,
FontFamily -> "Century Gothic", ShowAutoStyles -> False,
ShowSyntaxStyles -> False, AutoNumberFormatting -> False}}]},
StyleDefinitions -> "PrivateStylesheetFormatting.nb"
]
];
Style["Input Colour", 18, myColor]),

{myColor, Black},
{commentcolor, Purple},
{stringcolor, Brown},
{background, White},
{{size, 12, "size"}, 8, 20, 1}
]


Edit

re: questions from @R.M and @jmlopez

"Do you also know if it is possible to copy all the definitions from a stylesheet to the private stylesheet?"

I'm not actually sure what this question means. Stylesheet settings are inherited. The first cell in a private stylesheet

 Cell[StyleData[StyleDefinitions -> "Default.nb"]


means the stylsheet is taking its styles from the default stylesheet. So you don't have to copy over any styles. If your private stylesheet is based on one of the nested stylesheets you would insert e.g.

StyleData[
StyleDefinitions ->
FrontEndFileName[{"Creative"}, "NaturalColor.nb"]]


...and so on. If you want to define multiple styles then

SetOptions[EvaluationNotebook[],
StyleDefinitions -> Notebook[
{Cell[StyleData[StyleDefinitions -> "Default.nb"]],
Cell[StyleData["Input"],
...

]
Cell[StyleData["Output"],
...

]

Cell[StyleData["Text"],

...
] etc.


If you want to create a stand alone stylesheet programmatically then

nb = CreateDocument[
Notebook[{Cell[StyleData[StyleDefinitions -> "Default.nb"]],
Cell[StyleData["Input"], FontColor -> myColor]},
StyleDefinitions -> "PrivateStylesheetFormatting.nb"],
WindowSize -> All];
NotebookSave[nb, "mystylesheet.nb"]


You can now distribute "mystylesheet.nb"

-
Really nice answer! Live updating of the style sheet doesn't quite work on my system; I see something like this as I drag the size slider, but it refreshes as soon as a start to scroll the window for example. –  Mr.Wizard Jul 1 '12 at 13:28
On mine (OS X 10.6.8 and 8.0.4) updating is instantaneous. When are you going to get V8??!! (...although maybe it is your computer?) –  Mike Honeychurch Jul 1 '12 at 13:33
Impressive answer! –  Silvia Jul 1 '12 at 13:41
Very impressive! Do you also know if it is possible to copy all the definitions from a stylesheet to the private stylesheet? The reason I ask is that if you share your notebook with someone, it gives a file not found error for them because they don't have your stylesheet. If I can, with the click of a button, copy the contents over to the private stylesheet, then I can easily share –  The Toad Jul 1 '12 at 14:44
As @R.M mentioned, we do need an export functionality so that once we have decided on the style we can simply get the stylesheet we want to give out to other people. I like your answer by the way Mike. –  jmlopez Jul 1 '12 at 14:47

A style sheet is nothing more than a specific sequence of Mathematica Cell and StyleData expressions. An excerpt looks like this:

Cell[StyleData["SmallText", "Presentation"],
CellMargins->{{60, 10}, {9, 9}},
LineSpacing->{1, 5},
FontSize->18]

Cell[StyleData["SmallText", "Condensed"],
CellMargins->{{8, 10}, {5, 5}},
LineSpacing->{1, 2},
FontSize->9]

Cell[StyleData["SmallText", "Printout"],
CellMargins->{{2, 2}, {5, 5}},
TextJustification->0.5,
Hyphenation->True]


There is no reason these expressions cannot be generated programmatically using the familiar tools of expression construction and manipulation. If you have a style sheet that needs frequent changes create a meta-stylesheet program that builds the desired style sheet with whatever parameters you give it.

-
I don't think this answers the question (or if it does, it's not clear to me). The question was not on how to programmatically generate stylesheets, but how to include functions in them. How would you, for example, add the following function in the input style BackgroundColor -> RGBColor[1,0,"current minute"/60], so that a new input cell has a different colour based on when it is created? –  The Toad Jul 1 '12 at 14:38
@R.M I based my answer on: "The reason I would like to do this is that later on, if I change the color, every style that depends myColor will automatically change." –  Mr.Wizard Jul 2 '12 at 0:10

I believe it is like what @R.M said in the comments. And I agree with @Mr.Wizrd suggestion of using a meta-stylesheet. But in case you just want to do this in one stylesheet (eg. restrict in the private one), this is how I did:

Open a new plain notebook "nb", in its private stylesheet, create three style like this:

Cell[StyleData["color"],
FontColor->RGBColor[1,0,0]]

Cell[StyleData["style1"],
FontSize->30,
FormatType->color]

Cell[StyleData["style2"],
FontSlant->"Italic",
FormatType->color]


You may find that style1 and style2 is still without color. It's because color style is not defined for this stylesheet notebook but for "nb".

Now in "nb" you can create cells with style1 and style2:

Cell["This is style1.", "style1"]

Cell["This is style2.", "style2"]


You can see it has been correctly formated. And if you change the color in color style definition cell, color of style1 and style2` will both be changed.

(Obviously this method works fine for simple case, but still far from what if macros or variables would achieve :( )

-
This is actually something I wanted to do but had no idea how to do it. I will be experimenting with a combination of this and Mike's answer. –  jmlopez Jul 1 '12 at 14:49