# How to create a notebook element that can replace itself?

I would like to create a notebook element that can replace itself.

Here's an example to illustrate:

Panel[Column[
{Style["This is a panel", Bold],
Button["Press me!",
SelectionMove[EvaluationNotebook[], All, EvaluationCell];
NotebookWrite[EvaluationNotebook[],
"\"Now I'm just a piece of static text.\""]]}]]


This code will create a little panel:

If we press the button, the panel will get replaced by a piece of static text (i.e. not a dynamic expression that's shown as text, but just plain old non-dynamic text).

Well, in this implementation actually it's not the panel that gets replaced, but the complete cell containing the panel, and that's my problem: I need only the panel to be replaced, so this will work even if the panel is just a subexpression in a larger expression.

How can we create an UI control that is able to replace itself with an arbitrary expression in the notebook?

-
This is at least the second time I've read a question without noting the author, and thought "This is probably one for Szabolcs to answer." afterward to see you're asking. –  Mr.Wizard May 30 '12 at 7:44
@Mr.Wizard I thought the same thing. –  Heike May 30 '12 at 7:52
@Heike :-) -- can you think of any native object that has the behavior Szabolcs describes? I'm drawing a blank. –  Mr.Wizard May 30 '12 at 7:56
@Mr.Wizard Yes, there is one, and I should have mentioned it! It is the image cropping GUI. I'm not sure if it's available in 7. Paste an image into the notebook, right click, and select Crop Image. You can adjust the crop boundaries, and double-clicking it will replace the control with the cropped image. If I remember right, last time I checked this was implemented in terms of an undocumented native control that does almost everything alone, and not in terms of low-level Dynamic constructs. –  Szabolcs May 30 '12 at 7:59
Nope, not in v7. –  Mr.Wizard May 30 '12 at 8:00

This solution relies on putting a TagBox with a custom tag around the part to be replaced, reading the cell and replacing the tag, then writing it back. Personally I've always felt that the need to read the entire cell and write it all again seems kind of clunky, but I don't know of a better way to do this.

MakeBoxes[replacementMarker[a_,tag_],StandardForm]^:=TagBox[MakeBoxes[a],tag]

replaceMark[rule_,nb_:EvaluationNotebook[],which_:All,cell_:EvaluationCell]:=(
SelectionMove[nb,which,cell];

Row[{"Not replaced",
replacementMarker[
Panel[Column[{Style["This is a panel",Bold],Button["Press me!",
replaceMark[TagBox[_,"replacementTag"] :> MakeBoxes["\" Now I'm just text. \""]]
]}]]
,"replacementTag"]
,"Not replaced"}]


Important note! The action cannot be undone, so if used for example to allow dynamic reformatting of data or similar, be aware that mistakes can end up deleting the old contents.

-
Quite clever! +1 –  Mr.Wizard May 30 '12 at 8:01
Thanks. I can't say I like it, it just feels dangerous to be re-writing an entire cell when there's no undo, unless of course the contents aren't important or can be regenerated quickly. –  jVincent May 30 '12 at 8:13