The Cell Attachment Interface

Jason Abernathy, Front End Developer

Join the Conversation #WolframTechConf

Abstract

The cell attachment interface is a set of Wolfram language functions that allow the development of useful user interface elements. By attaching cells to arbitrary front end objects, context specific menus and toolbars can be implemented. The following topics will be discussed: details of the function signatures, along with their option values; an account of the use of the interface throughout the Mathematica front end; and some thoughts about future development.

UI Design

Dialog windows are going away, in favour of contextual menus.

consume screen real estate

often provide too many / irrelevant options

NotebookOpen["BasicMathAssistant.nb"];

UI Design ...

Other constructs are better, but still have drawbacks.

Manipulate[
Graphics3D[Sphere[],
PlotLabel->label,
Lighting->lighting,
Boxed->False,
ImageSize->Small
],
{label},
{lighting,{
{{"Point",Yellow,{3,3,5}}}->"Sun",
{{"Point",Blue,{3,3,5}}}->"Moon",
"Neutral"->"Neutral"
}},
ControlPlacement->Bottom]

A Better Way

"Press Me"

How We Use It

Code Assist Menu

Sin

Image Editor

Predictive Interface / Suggestions Bar

1+1

Cell Group Opener / Toggler

How to Use It

A definition for this presentation.

AttachCell[args___]:= MathLink`CallFrontEnd[FrontEnd`AttachCell[args]]

How to Use It

A definition for this presentation.

AttachCell[args___]:= MathLink`CallFrontEnd[FrontEnd`AttachCell[args]]

(1^st) and (2^nd) arguments are the parent object and cell being attached, respectively.

AttachCell[
EvaluationCell[],
Cell[BoxData[ToBoxes[]]]
]

NotebookDelete[%];

Positioning

(3^rd) and (4^th) arguments specify anchors.

AttachCellAt[args___]:= AttachCell[EvaluationNotebook[],,args,]

The parent anchor is prefixed by an offset.

AttachCellAt[{Automatic,Bottom},Bottom];

Positioning ...

Anchors with offsets.

AttachCellAt[{Automatic,{Right,Bottom}},Center];
AttachCellAt[{Scaled[-0.2],{Right,Bottom}},Center];
AttachCellAt[{Offset[{-100,-100},Scaled[-0.2]],{Right,Bottom}},Center];

Positioning ...

Notebook (does not scroll - attaches to the Notebook window)

(RowDefault["Show", "Hide"])

Cell or Box (scrolls)

(RowDefault["Show", "Hide"])

Making an Interface

Reference the parent object with AttachedCellParent[].

CurrentValue[AttachedCellParent[],Background]

Deploy[Panel[Column[{
Labeled[ColorSetter[Dynamic[CurrentValue[AttachedCellParent[],Background]]],"Background",Left],
Labeled[SetterBar[Dynamic[CurrentValue[AttachedCellParent[],CellMargins]],{0,20,40}],"Margins",Left],
Button["Reset",
CurrentValue[AttachedCellParent[],Background]=Inherited;
CurrentValue[AttachedCellParent[],CellMargins]=Inherited;
]
}]]]

({{(Labeled[Swatch, "Background"])}, {(Labeled[({{0, 20, 40}}), "Margins"])}, {"Reset"}});

Make an Interface ...

My Example Cell

AttachCell[
First[Cells[CellTags->"ExampleCell2"]],
Cell[BoxData[ToBoxes[%]]],
{Automatic,Bottom},Top
]

NotebookDelete[%]

Automatic Dismissal

Manually removing attached cells: ☹

Automatically removing attached cells: ☺

Revisit the first example.

Deploy@Panel@Column[{
Labeled[InputField[Dynamic[CurrentValue[AttachedCellParent[],PlotLabel]],String],"Label",Left],
Labeled[SetterBar[Dynamic[CurrentValue[AttachedCellParent[],Lighting]],{
{{"Point",Yellow,{3,3,5}}}->"Sun",
{{"Point",Blue,{3,3,5}}}->"Moon",
"Neutral"->"Neutral"
}
],"Lighting",Left]
}]

sphereEditor=({{(Labeled[, "Label"])}, {(Labeled[({{Point"Sun", Point"Moon", Neutral"Neutral"}}), "Lighting"])}});

Automatic Dismissal ...

Use the "ClosingActions" option.

Graphics3D[EventHandler[Sphere[],"MouseClicked":>AttachCell[,
"ClosingActions"->{"SelectionDeparture"}
],PassEventsDown->True],]

Automatic Dismissal ...

More "ClosingActions" options

({{“EvaluatorQuit”, the default Notebook kernel has been Quit.}, {“MouseExit”, the mouse cursor has left the bounds of the attached cell.}, {“OutsideMouseClick”, the mouse has been clicked outside of the attached cell.}, {“ParentChanged”, the parent object has been modified (edited, etc).}, {“SelectionDeparture”, the Notebook selection has changed.}, {“CellGroupOpened”, the group opened by the parent cell has been opened.}})

Taking it to the Limit

Dynamics / Animation

expression=Animate[Plot[Sin[x+a],{x,0,10}],{a,0,5},AnimationRunning->False];

AttachCell[
EvaluationNotebook[],
Cell[BoxData[ToBoxes[expression]]],
{None,Center},
Center,
"ClosingActions"->{"OutsideMouseClick"}
];

Suggestions

Follow this link: https://www.wolfram.com/support/contact/email/

Questions / Comments

jasona@wolfram.com

Thank You

Advanced Example

Ticker Info

Dynamically show the historical stock price of a ticker symbol that is clicked in a Notebook.

nb=CreateDocument[];

Validate a ticker symbol:

validTickerQ[sym_String]:=NumericQ[Quiet@FinancialData[sym]];
validTickerQ[___]:=False;
validTickerQ[""]:=False;
validTickerQ["Shares"]:=False;

validTickerQ["ZZZ123ZZZ"]
validTickerQ["TSLA"]

Ticker Info ...

Get a plot of a ticker symbol’s historical price

makeFinancialBoxes[sym_String]:=ToBoxes[DateListPlot[FinancialData[sym,"Jan. 1, 2000"],PlotLabel->"Historical Closing Value for "<>sym,Background->White,FrameLabel->{None,"USD"}]];

makeFinancialBoxes["TSLA"]//ToExpression

Ticker Info ...

Extend and read the current selection:

getSelectedWord[nb_NotebookObject]:=(SelectionMove[nb,All,Word];NotebookRead[nb]);

Check if the selection has changed:

wordChanged[sel_String]:=If[SameQ[sel,lastWord],False,lastWord=sel;True];
wordChanged[___]:=False;

Ticker Info ...

Create, and attach a cell if the selection has changed:

handleSelectionChanged[sel_]/;wordChanged[sel]&&validTickerQ[sel]:=(
MathLink`CallFrontEnd[FrontEnd`AttachCell[
nb,
Cell[BoxData[makeFinancialBoxes[sel]]],
{Automatic,{Right,Bottom}},
{Right,Bottom},
"ClosingActions"->{"OutsideMouseClick","SelectionChanged"}
]]
);

handleSelectionChanged[getSelectedWord[nb]];

Ticker Info ...

Make it happen!

CurrentValue[nb,NotebookDynamicExpression]=
Dynamic[
CurrentValue["MouseButtonTest"];
handleSelectionChanged[getSelectedWord[EvaluationNotebook[]]]
];