2
$\begingroup$

My DockedCellstoolbar has a self-closing button that sometimes decides to permanently stop working on that particular notebook. closing and reopening file always loads all previous toolbar even when restarting kernel or frontend which is bad enough for the end user but even worse for the developer who then must copy all code to a new notebook to evaluate his edits.

The following function pulled out from the last button is the only way i know to close a docked cell from a button within the docked cell. A quick look reveals a few problems. It doesnt just target my toolbar. It removes all custom toolbars even those useless native ones.

Function[Null, 
 SetOptions[EvaluationNotebook[], DockedCells -> Inherited, 
  TaggingRules -> Inherited, CellContext -> Inherited]]
 

The following is a greatly trimmed version of my toolbar given to provide a more complete picture of how i use it.`

toolbar[cellbg_ : RGBColor[.8, .85, 1, 1]] := Block[{},
   
   cellbuttons = Row[{
      Button["go to top", FrontEndTokenExecute["ScrollNotebookStart"]],
      Button["go to bottom", 
       FrontEndTokenExecute["ScrollNotebookEnd"]],
      Button["close toolbar", 
       Function[Null, 
        SetOptions[EvaluationNotebook[], DockedCells -> Inherited, 
         TaggingRules -> Inherited, CellContext -> Inherited]]]
      }];
   
   Echo[cellbuttons];
   
   SetOptions[
    EvaluationNotebook[],
    DockedCells -> Cell[
       BoxData[ToBoxes[cellbuttons]],
       "DockedCell",
       Background -> cellbg,
       CellMargins -> 0, 
       CellFrame -> {{0, 0}, {2, 2}},
       CellFrameMargins -> {{20, 0}, {2, 2}}
       ];
    
    ]];

toolbar[];

My questions are...

1.how can i rewrite the function so that it only targets my toolbar preferably by identifying it with cell tags.

  1. resetting options isn't very reliable. why isn't possible to just delete the offending code like we do with everything else in life? there has to be a better way.

Note: I could not get the trimmed down code to install (this explains the echo) but that is not the important part. what i really need is how to make the close function in the button more reliable.

$\endgroup$
4
  • 2
    $\begingroup$ You can selectively delete docked cells using DeleteCases with a suitable pattern or similar. I'd also suggest to consider adding your toolbar using AppendTo[CurrentValue[EvaluationNotebook[],DockedCells],…]. And regarding the issue with removing the cells: Can you check the settings for DockedCells for $FrontEndSession and $FrontEnd? I've sometimes had it happen that option values made their way "upwards" in the inheritance chain $\endgroup$
    – Lukas Lang
    Jul 5, 2021 at 7:56
  • $\begingroup$ @LukasLang thank you for your suggestions, ill give it a try. $\endgroup$ Jul 12, 2021 at 18:34
  • $\begingroup$ @LukasLang thank you AppendTo worked! here is what replaced SetOptions. AppendTo[ CurrentValue[EvaluationNotebook[], DockedCells], Cell[ BoxData[ToBoxes[nbtaskmategrid]], "DockedCell", Background -> cellbg, CellMargins -> 0, CellFrame -> frame, CellFrameMargins -> marg, CellFrameColor -> coalt ]];` $\endgroup$ Jul 25, 2021 at 20:19
  • $\begingroup$ @LukasLang finally got around to trying out selectively c;losing docked by their unique properties, The problem is I first need to tocate docked which Cells and NotebookFind cannot seem to do. More details here: mathematica.stackexchange.com/questions/272033/… $\endgroup$ Aug 13, 2022 at 7:23

1 Answer 1

2
$\begingroup$

Use NotebookDelete[EvaluationCell[]] instead of manipulating the DockedCells option:

toolbar[] := 
  With[{cellbuttons = 
     Row[{Button["go to top", FrontEndTokenExecute["ScrollNotebookStart"]], 
       Button["go to bottom", FrontEndTokenExecute["ScrollNotebookEnd"]], 
       Button["close toolbar", NotebookDelete[EvaluationCell[]]]}]},
   SetOptions[EvaluationNotebook[], DockedCells -> Inherited];
   SetOptions[EvaluationNotebook[], 
    DockedCells -> {Cell[BoxData[ToBoxes[cellbuttons]], "DockedCell"]}]];

toolbar[];

The first SetOptions is needed, because after NotebookDelete[EvaluationCell[]] the value of the DockedCells option isn't changed, and setting it again to the same value has no effect (the deleted docked cell isn't restored).

Since NotebookDelete[EvaluationCell[]] doesn't change the value of the DockedCells option, the removed toolbar will be restored after saving and reopening the Notebook. In order to remove the toolbar completely, one should remove it from DockedCells. Here is one possible implementation (it is assumed that docked cells cannot have the same contents):

toolbar[] := 
  Block[{cellbuttons = 
     Row[{Button["go to top", FrontEndTokenExecute["ScrollNotebookStart"]], 
       Button["go to bottom", FrontEndTokenExecute["ScrollNotebookEnd"]], 
       Button["close toolbar", 
        SetOptions[EvaluationNotebook[], 
         DockedCells -> 
          DeleteCases[Flatten[{CurrentValue[DockedCells]}], 
           Cell[First@NotebookRead[EvaluationCell[]], __]]]]}]}, 
   SetOptions[EvaluationNotebook[], 
    DockedCells -> {Cell[BoxData[ToBoxes[cellbuttons]], "DockedCell"]}]];

toolbar[];

With this implementation, after clicking the "close toolbar" button, CurrentValue[DockedCells] will return empty list {} if there was only one docked cell. This implementation is based on the assumption that NotebookRead returns the same for the first argument of Cell as it is specified in the value of DockedCells option. I'm not sure however that this assumption always holds, hence it is possible that this method fails in some rare cases which normally should not appear in practice. At the same time, the method via NotebookDelete[EvaluationCell[]] will always work as expected. These two methods can be used simultaneously.

And here is a robust implementation based on the official resource submission template:

toolbar[] := 
  With[{boxID = CreateUUID[], 
    pol = Polygon /@ {RotationTransform[Pi/4]@#, 
         RotationTransform[3 Pi/4]@#} &@{{-5, -1}, {-5, 1}, {5, 1}, {5, -1}}}, 
   With[{cellbuttons = 
      Grid[{{Button["go to top", FrontEndTokenExecute["ScrollNotebookStart"]], 
         Button["go to bottom", FrontEndTokenExecute["ScrollNotebookEnd"]], 
         MouseAppearance[
          Button[MouseAppearance[
            PaneSelector[{False -> 
               Graphics[{GrayLevel[64/85], pol}, ImageSize -> 18, PlotRange -> 7], 
              True -> Graphics[{GrayLevel[128/255], pol}, ImageSize -> 18, 
                PlotRange -> 7]}, Dynamic[CurrentValue["MouseOver"]]], "LinkHand"], 
           CurrentValue[EvaluationNotebook[], DockedCells] = 
            DeleteCases[Flatten[{CurrentValue[EvaluationNotebook[], DockedCells]}], 
             c_Cell /; ! FreeQ[c, boxID]], BoxID -> boxID, Appearance -> None], 
          "LinkHand"]}}]},
    CurrentValue[EvaluationNotebook[], DockedCells] = 
     Cell[BoxData[ToBoxes[cellbuttons]], "DockedCell"]]];

toolbar[];

screenshot

Note that it uses undocumented option BoxID to find the current docked cell.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.