7

Other than the GroupOpener triangle, are there anyways to change how a cell (that is the parent cell of a group) looks when its group is collapsed or expanded?

Specifically, using the stylesheet could I toggle the background of a cell between White and LightBlue when the group is closed and opened?

enter image description here

user5601
  • 3,573
  • 2
  • 24
  • 56
  • slightly related: 73375 – Kuba Mar 02 '17 at 21:06
  • 1
    The only way I can think to do this would be to have a function that scans the Notebook for cell states and restyles open as open, closed as closed. This would either need to be a manually run process or set to run at some point like when the Notebook is opened. Would such a solution be of any use to you? – Mr.Wizard Mar 02 '17 at 21:16
  • 1
    It would be nice to have Tokens/CurrentValues to handle CellGroup related activities :( – Kuba Mar 03 '17 at 09:08

3 Answers3

4

I haven't figured out how to do this with styles yet but I feel as though I have made significant progress and I want to share it. Please try:

t1 = True;

Notebook[{Cell[
    CellGroupData[{
      Cell["Parent", "Section", 
        Background -> Dynamic[If[t1, LightRed, LightBlue]]], 
      Cell["Fee", "Subsection"],
      Cell["Fi", "Subsection"],
      Cell["Fo", "Subsection"],
      Cell["Fum", "Subsection"]
    }, Dynamic[t1]]
]}] // NotebookPut

enter image description here

enter image description here

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • @kglr (1) my first version was changing the content rather than the background, but I realized(?) that user5601 probably didn't want that and was only using the cell names for illustration. (2) With your code in 10.1.0 I get errors instead of "Open" or "Closed" -- don't we need a BoxData expression? I mean like http://mathematica.stackexchange.com/revisions/139083/1 – Mr.Wizard Mar 02 '17 at 22:35
  • the code in my deleted comment does not give errors in V9, but it does not update the content (content stays "Open"). With BoxData + DynamicBox it does toggle the content. – kglr Mar 02 '17 at 23:17
  • 1
    Very neat! FYI it's not True/False but Open/Closed now (now = v12.1). – Silvia Mar 19 '20 at 08:55
4

Here is a style sheet solution:

Notebook[
    {
    Cell[StyleData[StyleDefinitions->"Default.nb"]],
    Cell[StyleData["Section"],
        ShowGroupOpener->True,
        CellContext->Cell,
        CellDynamicExpression :> With[{cell = NotebookRead[EvaluationCell[]]},
            NotebookWrite[EvaluationCell[], Cell[""], All];
            NotebookWrite[
                EvaluationNotebook[],
                Cell @ CellGroupData[
                    {
                    Replace[cell,
                        Cell[b_, "Section", ___] :>
                        Cell[b, "Section",
                            CellDynamicExpression:>None,
                            Background->Dynamic[If[open, White, LightBlue]]
                        ]
                    ]
                    },
                    Dynamic[open]
                ]
            ];
            FrontEndTokenExecute["MovePrevious"]
        ]
    ]       
    },
    Saveable->False,WindowSize->{808,689},WindowMargins->{{Automatic,143},{40,Automatic}},
    FrontEndVersion->"10.3 for Mac OS X x86 (32-bit, 64-bit Kernel) (December 10, 2015)",
    StyleDefinitions->"PrivateStylesheetFormatting.nb"
];
NotebookPut @ %;

The first NotebookWrite is a hack so that the second NotebookWrite actually does what I want, which is to create a CellGroupData object with a Dynamic in it's second argument.

Carl Woll
  • 130,679
  • 6
  • 243
  • 355
  • @Kuba It works for me in 10.3 and 11.1 on OS X. Did you add additional cells below the "Section" cell and then close the group? If so, could you NotebookRead the cell group and tell me what you get? – Carl Woll Mar 03 '17 at 14:53
  • Sorry, something must have interfered earlier, now everything works as expected. +1 – Kuba Mar 03 '17 at 15:36
  • There is no CellDynamicExpression because I insert CellDynamicExpression:>None explicitly. And it works without children, although naively one wouldn't expect it to. – Carl Woll Mar 03 '17 at 15:45
  • Ok, I don't have time to investigate and somehow sometimes I run into problems. Will delete comments and reply if I trace this. – Kuba Mar 03 '17 at 15:49
  • Fascinating code! Off hand do you have an idea of the overhead that this method will incur in larger Notebooks? – Mr.Wizard Mar 06 '17 at 05:29
  • 1
    @Mr.Wizard I think the overhead should be minimal. After the Section is created, the CellDynamicExpression used to create the dynamic variable controlling the background color is disabled. The dynamic controlling the background color only gets activated when the cell group is opened or closed. – Carl Woll Mar 06 '17 at 06:12
1

Here is a starting point. I have yet to find out how to detect cell group state without NotebookRead it.

So place this code below e.g. a Section cell and evaluate. You can incorporate it in a stylesheet too, but it isn't ready for that imo.

SetOptions[
    PreviousCell[]
  , "ShowGroupOpener" -> False
  , Background -> Red
  , CellDingbat -> Cell[
        BoxData@ToBoxes@EventHandler[Dynamic@Opener[]
          , {
            "MouseClicked" :> With[{ec = EvaluationCell[]}
              , SelectionMove[ec, All, Cell]
              ; FrontEndExecute@FrontEndToken[ec, "OpenCloseGroup"]
              ; SetOptions[ParentCell@ec, Background -> (
                    CurrentValue[ParentCell[ec], Background] /. 
                        {Red -> Blue, Blue -> Red})
                ]
             ]
           , PassEventsDown -> True
          }
        ]
      , Background -> None
    ]
]
Kuba
  • 136,707
  • 13
  • 279
  • 740