Creating Custom Interfaces with Mathematica

Andrew A. de Laix
Lead Developer: A New Kind of Science Explorer, Wolfram Research, Inc.

Mathematica UI Programming Skills

Button programming.

Front end scripting: top level functions and front end tokens (FrontEndExecute).

Notebook and cell options.

Style sheets.

A good resource for programming the front end: The Beginner's Guide to Mathematica, Glynn and Gray (ch. 63).

Detailed Example: The Export Dialog Box

Let's look at a particular element in detail: the export dialog box.  This dialog arises when a user select the "export image" button on the interactive form.

The code

\(ExportDialogNotebook[bd_] := 
      Notebook[{Cell[
            TextData[{Cell[
                  GraphicsData["Bitmap", "CF5dJ6E]HGAYHf4PAg9QL6QYHg<PAVmbKF5d0`40000A00003B000`400?l00000o`00003o00<0fID2
0=:@0P3>SP801P3>SP800`3BT080fID20=bG0P050=bG0P0000<0dY020;f20P2cN`801P2cN`80102f
O@80_X<20<R90P3FT`840=bG0P0000<0cXh20;=k0P3LU`801P3LU`801@3BT080_H8209a[0P2kP080
eY<200<0g9L200001P3>SP80/g/20=bG0P2OJ@00WFL009QT00<0UF8000H0SUd00:mh0P3LU`80g9L2
0;^00P3FT`820=bG0P0000H0cXh20;=k0P3LU`80WfT009QT0029FP03085E000707mD002XL`80g9L2
09mY003LU`80^h020=JC0P010=bG0P0000H0cXh20;=k0P3LU`80WfT009ER0021E@060=bG0P80WfT0
0@3LU`810;^00P40eY<200001`3>SP80/g/20=bG0P2OJ@00UF80085E003LU`80202OJ@010=bG0P40
cXd200001`3>SP80/g/20=bG0P2OJ@00UF80085E003LU`802@2OJ@010=bG0P0000L0cXh20;=k0P3L
U`80WfT009QT0029FP00g9L200P0WfT00P3LU`8000060<j>0P2cN`80g9L209mY002MI`00V6@01P3L
U`8209mY00<0g9L200000`3>SP80/g/20=bG0P0609mY000409QT002mPP80g9L209mY00@0g9L20000
0`3BT080_H820=bG0P0609mY000309eW003BT080g9L200D0g9L200000`3IU@80dY020=bG0P0>0=bG
0P00"], "Graphics", 
                  Background -> 
                    RGBColor[0.8599984740978104`, 0.5903257801174945`, 
                      0.008621347371633479`], Evaluatable -> False, 
                  GeneratedCell -> False, 
                  CellAutoOverwrite -> False, 
                  ImageSize -> {17.`, 13.`}, 
                  ImageMargins -> {{0.`, 0.`}, {0.`, 0.`}}, 
                  ImageRegion -> {{0.`, 1.`}, {0.`, 
                        1.`}}], "   Export Formats:"}], "Text", 
            CellMargins -> {{0, 0}, {0, 0}}, 
            FontColor -> GrayLevel[1], FontWeight -> "Bold", 
            FontFamily -> "Helvetica", CellBaseline -> Axis, 
            Background -> 
              RGBColor[0.8599984740978104`, 0.5903257801174945`, 
                0.008621347371633479`]], 
          Cell[TextData[
              ButtonBox["GIF  (.gif)", 
                ButtonStyle -> "ExportSetButton"]], "ExportSelectedText", CellTags -> "GIF"], 
          Cell[TextData[
              ButtonBox["JPEG (.jpg)", 
                ButtonStyle -> "ExportSetButton"]], "ExportText", CellTags -> "JPEG"], 
          Cell[TextData[
              ButtonBox["TIFF (.tif)", 
                ButtonStyle -> "ExportSetButton"]], "ExportText", CellTags -> "TIFF"], 
          Cell[TextData[
              ButtonBox["EPS  (.eps)", 
                ButtonStyle -> "ExportSetButton"]], "ExportText", CellTags -> "EPS"], 
          Cell[TextData[{"For personal use only.  For any other use visit:
", ButtonBox["www.wolframscience.com/nksx/permissions", 
                  RuleDelayed[ButtonData, 
                    List[URL["http://www.wolframscience.com/nksx/permissions"], None]], Rule[ButtonStyle, "Hyperlink"]]}], "Text", 
            TextAlignment -> Center, 
            Background -> RGBColor[0.98439, 0.937514, 0.394537], 
            CellMargins -> {{0, 0}, {0, 0}}, 
            CellFrameColor -> 
              RGBColor[0.8599984740978104`, 0.5903257801174945`, 
                0.008621347371633479`], CellFrame -> 1], 
          Cell[BoxData[
              GridBox[{{ButtonBox["Save", 
                      ButtonFunction :> \((SaveGraphicsBF[#] &)\), ButtonData -> bd, Active -> True, 
                      ButtonSource -> ButtonData, 
                      ButtonEvaluator -> Automatic], 
                    ButtonBox["Cancel", Active -> True, 
                      ButtonFunction :> 
                        NotebookClose[ButtonNotebook[]]]}}]], "Text", 
            FontFamily -> "Helvetica", 
            TextAlignment -> "Center", 
            CellFrame -> {{0, 0}, {0, 0}}, 
            CellFrameColor -> 
              RGBColor[0.8599984740978104`, 0.5903257801174945`, 
                0.008621347371633479`], CellFrameMargins -> 4, 
            CellMargins -> {{0, 0}, {4, 4}}]}, Editable -> False, 
        Deletable -> False, ShowSelection -> False, 
        WindowFrame -> "ModalDialog", WindowElements -> {}, 
        WindowFrameElements -> {"CloseBox"}, 
        WindowMovable -> False, WindowTitle -> None, 
        ShowCellBracket -> False, 
        StyleDefinitions -> "NKSStyles.nb", 
        WindowFloating -> False, 
        WindowSize -> {350, FitAll}]\)

\(ExportSetButtonBF[
        x1_] := \((SetOptions[ButtonNotebook[], 
          Editable -> True]; 
NotebookFind[
          ButtonNotebook[], "ExportSelectedText", All, 
          CellStyle]; 
FrontEndExecute[{FrontEndToken[
              ButtonNotebook[], "Style", "ExportText"]}]; 
SelectionMove[ButtonNotebook[], All, 
          ButtonCell]; 
FrontEndExecute[{FrontEndToken[
              ButtonNotebook[], "Style", "ExportSelectedText"]}]; $NKSExportFormat = 
          CellTags /. Options[NotebookSelection[ButtonNotebook[]], CellTags]; 
        SetOptions[ButtonNotebook[], Editable -> False];)\)\)

Emulating Radio Buttons

Mathematica doesn't currently provide any type of radio style button.  We choose to emulate them using a combination of ordinary buttons and cells:

({{\(Cell[
            TextData[
              ButtonBox["GIF  (.gif)", 
                ButtonStyle -> "ExportSetButton"]], 
"ExportSelectedText", CellTags -> "GIF"]\)}, {\(Cell[
            TextData[
              ButtonBox["JPEG (.jpg)", 
                ButtonStyle -> "ExportSetButton"]], 
"ExportText", CellTags -> "JPEG"]\)}})

Each cell is a different radio button.

Cell styles set the appearance of each button.

When clicked, the button function updates the selected button style and resets the previously selected button to the unselected style.

Radio Button Function

ExportSetButtonBF[x1_]:=
(SetOptions[ButtonNotebook[], Editable -> True];
NotebookFind[
            ButtonNotebook[], "ExportSelectedText", All, CellStyle] (*Find currently selected button and…*) ;
\(FrontEndExecute[{FrontEndToken[
                ButtonNotebook[], \*""Style","ExportText""]}]\) (*reset it to the unselected style.*) ;
SelectionMove[ButtonNotebook[], All, 
            ButtonCell] (*Select the current button cell and…*) ;
FrontEndExecute[{FrontEndToken[
                ButtonNotebook[], "Style", "ExportSelectedText"]}]  ;
$NKSExportFormat = 
            CellTags /. 
              Options[NotebookSelection[ButtonNotebook[]], CellTags] (*set an internal variable with the new format*) ;
SetOptions[ButtonNotebook[], 
            Editable -> False];)

Other Buttons in the Dialog

Permissions URL

\(ButtonBox["www.wolframscience.com/nksx/permissions", 
      ButtonData :> {URL["http://www.wolframscience.com/nksx/permissions"], None}, 
      ButtonStyle -> "Hyperlink"]\)

Save button

ButtonBox["Save", 
      ButtonFunction :> (SaveGraphicsBF[#] &), 
      ButtonData -> bd, Active -> True, 
      ButtonSource -> ButtonData, 
      ButtonEvaluator -> Automatic]

The button data was generated on the fly and contains the graphics data from the image to be exported.

Cancel button

ButtonBox["Cancel", Active -> True, 
      ButtonFunction :> 
        NotebookClose[ButtonNotebook[]]]

Window Options

These options give our dialog an appearance less like a typical notebook and more like a true dialog box:

({{Editable -> False, not editable}, {Deletable -> False, cannot delete any element}, {ShowSelection -> False, do not show selection}, {WindowFrame -> "ModalDialog", give frame a modal dialog appearence}, {WindowElements -> {}, no scroll bars,  resize area, etc.}, {WindowFrameElements -> {"CloseBox"}, just a close box button}, {WindowMovable -> False, immobile}, {WindowTitle -> None, no title}, {ShowCellBracket -> False, no cell brackets}, {StyleDefinitions -> "NKSStyles.nb", use NKSStyles . nb for style sheet}, {WindowFloating -> False, do not float above other windows }, {WindowSize -> {350, FitAll}, fix to an appropriate size}})