1
$\begingroup$

Request 1: A workaround for Cells or NotebookFind needs to be found for locating and returning the CellObject-s of DockedCells with identifying cell properties like CellID or CellTags. Someone out there knows what to do. If you know of a way no matter how hackey please help.

Request 2: If you believe this is a bug with Cells or NotebookFind or should be considered one or is missing expected functionality, please alert me and I will happily submit a bug report or a request for feature enhancement to the Wolf

For plenitude I am coding a DockedCells toolbar remover which defaults to the nuclear option (removes all docked) but can selectively only remove single docked when given an identifying property such as CellTags or CellID. The code is irrelevant but given in case you need it to clean up after testing your solutions to this.`

ClearAll[RemoveDocked]
RemoveDocked[spec_ : "Nuclear", prop_ : CellTags] := Module[{},
   (* nucLear option removes all docked *)
   If[(MatchQ[spec, All] || 
      StringMatchQ[spec, "nuclear" | "nuke", 
       IgnoreCase -> True]), (SetOptions[EvaluationNotebook[], 
      DockedCells -> Inherited]; Return[])];
   (* here is where code for removing individual docked would be placed *)
   Echo[spec, "spec \[RightTeeArrow]"];
   ];

Below are the sample DockedCells toolbars I coded to test my CellObject locators, which by the way work fine on Input cells but return empty list {} for Cells and $Failed forNotebookFind.

ClearAll[ops, bops, txt, but, nuk]
ops = Sequence[FontSize -> 16, FontColor -> White, 
   FontFamily -> "Courier New", Background -> Darker@Darker@Blue, 
   CellFrameMargins -> 7, ShowCellTags -> False];
bops[col_ : Black, bg_ : None] := 
  Sequence[BaseStyle -> {12, col, Bold}, Background -> bg];
txt = Cell[
   "This is only plain text. No boxes were harmed in making this.", 
   "DockedCell", ops, CellID -> 111, CellTags -> "txt"];
but = Cell[
  BoxData[ToBoxes[
    Row[{"Manually save your work or turn on autosave. ", 
      Button["NB Save", NotebookSave[], bops[]], " ", 
      Button["NB AutoSave", 
       SetOptions[EvaluationNotebook[], NotebookAutoSave -> True], 
       bops[]]}]]], ops, CellID -> 222, CellTags -> "but"];
nuk = 
 Cell[BoxData[
   ToBoxes[Row[{Style["Exercise Nuclear Option: ", Bold, Italic], 
      "the world will never be the same again. ", 
      Button["Unset All Docked", RemoveDocked["Nuclear"], 
       bops[White, Darker@Red]]}]]], ops, CellID -> 333, 
  CellTags -> "nuk"];
SetOptions[EvaluationNotebook[], DockedCells -> {txt, but, nuk}]

Below are my tests for finding DockedCells (first three in lists) with Cellsand NotebookFind. I used Input cells (last three in lists) as my experimental controls.

(* DockedCells return an enpty List {} or $Failed *)
(* Input Cells (last 3 in tags and ids) return a CellObject *)

ClearAll[tags, ids]
tags = {"txt", "but", "nuk", "cases1", "cases2", "del"};
ids = {111, 222, 333, 100, 200, 321};

(* with Cells *)
Echo[Cells[CellTags -> #] & /@ tags, "Cells by CellTags \[Rule] "];
Echo[Cells[CellID -> #] & /@ ids, "Cells by CellID \[Rule] "];

(* with NotebookFind *)
Echo[NotebookFind[EvaluationNotebook[], #, All, CellTags, 
     IgnoreCase -> True, WrapAround -> True] & /@ tags, 
  "NotebookFind by CellTags \[Rule] "];
Echo[NotebookFind[EvaluationNotebook[], #, All, CellID, 
     IgnoreCase -> True, WrapAround -> True] & /@ ids, 
  "NotebookFind by CellID \[Rule] "];
$\endgroup$
8
  • 1
    $\begingroup$ This is not a bug. The way to manipulate the content is via the DockedCells option on the notebook. $\endgroup$
    – ihojnicki
    Commented Aug 13, 2022 at 11:24
  • 1
    $\begingroup$ @ihojnicki Actually, it is possible to manipulate DockedCells also via the corresponding CellObjects, what can be more convenient in some cases. It is sad that there is no simple way to get these CellObjects. I hope it will be added in the future. $\endgroup$ Commented Aug 15, 2022 at 5:46
  • 2
    $\begingroup$ @AlexeyPopkov, adding a DockedCells option to Cells was considered when AttachedCells was added. I wouldn't hold out hope for it. @Jules Manson, removing a particular Cell from the DockedCells it is just a matter of list manipulation. Assuming it was programmatically added to the notebook in the first place. $\endgroup$
    – ihojnicki
    Commented Aug 15, 2022 at 12:04
  • 2
    $\begingroup$ @AlexeyPopkov, you can manipulate your CellObject all you want. Whatever you do will never be reflected back into the option though, which is simply a consequence of the design. $\endgroup$
    – ihojnicki
    Commented Aug 15, 2022 at 13:58
  • 2
    $\begingroup$ @AlexeyPopkov Sure, but EvaluationCell[] is the only robust way to do it. Otherwise, you are creating something that depends on initial preconditions. $\endgroup$
    – ihojnicki
    Commented Aug 15, 2022 at 14:39

1 Answer 1

2
$\begingroup$

Update: a straighforward solution

One could use the Initialization option of Cell to collect the required information:

SetOptions[EvaluationNotebook[], 
 DockedCells -> {Cell["DockedCell", "DockedCell", 
    Initialization :> 
     If[Head[$DockedCells] === List, $DockedCells = 
       Append[Select[$DockedCells, CurrentValue[#, CellID] =!= $Failed &], 
        EvaluationCell[]], $DockedCells = {EvaluationCell[]}]]}]

Instead of modifying DockedCells themself, one can change the default style for them with the same effect:

SetOptions[EvaluationNotebook[], 
 StyleDefinitions -> 
  Notebook[{Cell[StyleData[StyleDefinitions -> "Default.nb"]], 
    Cell[StyleData["DockedCell"], 
     Initialization :> 
      If[Head[$DockedCells] === List, $DockedCells = 
        Append[Select[$DockedCells, CurrentValue[#, CellID] =!= $Failed &], 
         EvaluationCell[]], $DockedCells = {EvaluationCell[]}]]}, 
   StyleDefinitions -> "PrivateStylesheetFormatting.nb"]]

Now $DockedCells returns the complete list of DockedCells' handles:

SetOptions[EvaluationNotebook[], 
  DockedCells -> {Cell["DockedCell_1", "DockedCell"], Cell["DockedCell_2", "DockedCell"], 
    Cell["DockedCell_3", "DockedCell"]}];

$DockedCells
First@NotebookRead[#] & /@ $DockedCells

screenshot

{"DockedCell_3", "DockedCell_2", "DockedCell_1"}

(I'm not sure why the list is reversed.)

With this approach it is easy to find a docked cell by its CellID or CellTags, for example:

SetOptions[EvaluationNotebook[], 
  DockedCells -> {Cell["DockedCell_1", "DockedCell", CellTags -> "1"], 
    Cell["DockedCell_2", "DockedCell", CellTags -> "2"], 
    Cell["DockedCell_3", "DockedCell", CellTags -> "3"]}];

Select[$DockedCells, CurrentValue[#, CellTags] == "1" &]

output


Original answer

Since DockedCells support Dynamic, you can use EvaluationBox[] and EvaluationCell[] to get the handle. For example:

CreateWindow[
 DockedCells -> 
  Cell[BoxData@
    ToBoxes@Button["my box", 
      NotebookWrite[EvaluationNotebook[], 
       Cell[BoxData@ToBoxes@EvaluationCell[], "Input"]]], "DockedCell"]]

screenshot

One could also use the DynamicWrapper trick as in the ResourceFunction["PrintAsCellObject"]:

CreateWindow[DockedCells -> Cell[BoxData@ToBoxes@DynamicWrapper["DockedCell",
                                       cell = EvaluationCell[ ],
                                       SingleEvaluation -> True,
                                       DestroyAfterEvaluation -> True
                       ], "DockedCell"]]

screenshot


Additional note

Cells created using AttachCell can only be found by Cells when the option AttachedCell -> True is specified, but this option is introduced only in version 13.0 (while AttachCell is introduced in 12.2). At the same time, AttachCell always return a CellObject corresponding to the cell created. Therefore, I would count the fact that Cells doesn't return the DockedCells as a missing functionality, and not a bug.

$\endgroup$
14
  • 1
    $\begingroup$ @JulesManson I've added an example on the bottom of the "Update" section. $\endgroup$ Commented Aug 15, 2022 at 10:41
  • 1
    $\begingroup$ @JulesManson Yes, you can combine all style definitions in one custom stylesheet. $\endgroup$ Commented Aug 15, 2022 at 13:05
  • 1
    $\begingroup$ @JulesManson After testing I think it is more robust to use CurrentValue[#, CellID] =!= $Failed & as a test for validity of a CellObject, instead of Developer`CellInformation[#] =!= $Failed &. Changed the answer accordingly. Thanks for the Accept. $\endgroup$ Commented Aug 17, 2022 at 3:02
  • 1
    $\begingroup$ @JulesManson The test CurrentValue[#, CellID] =!= $Failed & is not a test for the presence of the CellID option (CurrentValue returns some default value when this option isn't set), it checks for the validity of a CellObject. In this sense it is absolutely equivalent to CurrentValue[#, CellTags] =!= $Failed & which just a bit longer to type. You can use any of them with the same effect. Developer`CellInformation has a drawback that it returns unevaluated for some inputs, and as a consequence the test Developer`CellInformation[#] =!= $Failed & can give false True. $\endgroup$ Commented Aug 17, 2022 at 5:27
  • 1
    $\begingroup$ @JulesManson It looks like you are goaing the hard way adding the "DockedCell" cell style to the pivate stylesheet. It could be done much easier just by manipulatin the option StyleDefinitions (simply append the new Cell to the list of Cells in the Notebook expression). If you aren't sure how it can be done, please open new question and I'll be happy to help you. $\endgroup$ Commented Aug 17, 2022 at 5:33

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.