21

Is there a way to create and edit notebooks (sequences of cells) in a tabbed interface? Could such an interface be made with TabView or some other tool? I assume this would be possible if I made a front-end from scratch, but is there a way within the standard Wolfram front-end?


Two things motivate me to ask this. First, I would like to create a replacement for Microsoft Office OneNote with Mathematica notebooks. Second, when I'm working in Mathematica I find myself wondering whether a tabbed interface would work better than having numerous separate windows open.

Andrew
  • 1,041
  • 1
  • 16
  • 24
  • 5
    Mathematica supports pagination of notebooks for presentations, and it also supports "docked cells" (always shown at the top). You may be able to combine the two to create a user interface in the docked cell for switching between the pages. This is just an idea for a starting point. – Szabolcs Jan 08 '12 at 17:37
  • I posted an answer that after thinking more about it only works for output. I think the quickest to do this would be to create a separate tab bar or palette that switches between windows by setting Visible->False for all but the selected window/notebook. This may give the illusion of a tabbed interface. – Mike Honeychurch Jan 08 '12 at 22:28
  • 3
    There is no built-in (native) tabbed interface in the *Mathematica* frontend user interface (but this is an excellent suggestion to report to support@wolfram.com). The nearest thing in the frontend user interface that I can think of, is the slide show environment (open the `Palettes` menu and select `Slide Show`). – Arnoud Buzing Jan 09 '12 at 00:27
  • 4
    @Mike Here's a starting point, but I expect this to get very messy ... ``PaletteNotebook@ DynamicModule[{nb}, Dynamic[nb = SelectedNotebook[]; SetterBar[Dynamic[nb, (SetSelectedNotebook[#]) &], SortBy[Thread[ Notebooks[] -> NotebookTools`NotebookName /@ Notebooks[]], Last]]]]`` – Szabolcs Jan 09 '12 at 19:48
  • Nice one @Szabolcs ! Where did you learn about the `NotebookTools` context? – Mike Honeychurch Jan 09 '12 at 21:12
  • 1
    @Mike I don't remember ... maybe I did ``?*`Notebook*`` or something like that. Much of it is identical to the (documented) `AuthorTools` package, see http://stackoverflow.com/q/8774123/695132 – Szabolcs Jan 09 '12 at 21:47
  • Ah! I did `?NotebookTools'*` and thought some of the functions looked familiar. I used to use `AuthorTools` a lot many years ago. – Mike Honeychurch Jan 09 '12 at 21:58
  • @Szabolcs I did `?*\`Notebook*` and found your gold mine -- but I'm having trouble actually getting to the namespaces: `NotebookTools\`` shows up in the result of `?*\`Notebook*`, but `Needs["NotebookTools\`"]` produces `Needs::nocont: Context NotebookTools`\ was not created when Needs was evaluated.` so it's hiding somewhere. Ditto `Get...` Clues? – Reb.Cabin Jan 18 '12 at 01:36
  • 1
    @Reb.Cabin There's no need to load anything, the symbols are already there. You just need to use ``NotebookTools`NotebookName[]`` and not `NotebookName[]`. You can read about contexts [here](http://reference.wolfram.com/mathematica/tutorial/Contexts.html). Of course you can add ``NotebookTools` `` to `$ContextPath` if you really wish. But please keep in mind that all this in undocumented functionality so there's no telling what going to happen to it in the next version, or even if it works without messing anything up in the current version (I burnt myself with other functions before ...) – Szabolcs Jan 18 '12 at 08:43

1 Answers1

10

While Mathematica doesn't support tabbed notebook windows directly, it is possible to reproduce something of the effect using DockedCells. The Virtual Book/Function Navigator interface (from the help menu) does this...it's essentially a slide show with two slides, one holding the VB and the other containing the FN, with a DockedCells navigation interface driven by NotebookFind that looks a bit like tabs.

Here's the gist of how you might go about making such a notebook on your own. Sorry, there are some kind of advanced concepts here...if there's any parts of this solution which you want to learn more about, maybe you can spin off more questions.

(* make a single page of the notebook *)
page[tag_String] := 
  Cell@CellGroupData[{Cell["", "SlideShowNavigationBar", 
      CellTags -> {tag}], Cell[tag, "Title"]}];
(* make a single tab-like button which selects the page *)
button[tag_String] := 
  Button[Dynamic[
    Setter[Dynamic[
      CurrentValue[EvaluationNotebook[], {TaggingRules, "page"}, 
       tag]], tag]], 
   CurrentValue[EvaluationNotebook[], {TaggingRules, "page"}] = tag; 
   NotebookLocate[tag], 
   Appearance -> None];
(* make a notebook based upon a list of strings which are names of tabs *)
makeTabbedNotebook[nameList_List] :=
  NotebookPut@Notebook[page /@ nameList,
    DockedCells -> 
     ToBoxes[ExpressionCell[Row[button /@ nameList], 
        "DockedCell"]][[1]], 
    ScreenStyleEnvironment -> "SlideShow"];

makeTabbedNotebook[{"First", "Second", "Third"}]

Edit: changed NotebookFind[ButtonNotebook[],tag,All,CellTags], which appears to not always scroll the slideshow correctly, to NotebookLocate[tag]. See discussion in comments. The two bits of code should, in theory, be equivalent, but a bug in Mathematica 8 appears to make them behave differently sometimes.

John Fultz
  • 776
  • 5
  • 11
  • 5
    John, I noticed on V 8.04, when I run the above, and it is now setting at 'First', then I click on 'Second', then the button shows it is now on 'second' but the page displays 'First'. But when I am on 'third' and click on 'second, then it does change ok. I am sure this is easy to fix, but your code is too advanced for me to figure it out now :). I can add screen shot, but do not know how to do it in comment. – Nasser Jan 17 '12 at 00:12
  • 3
    Replacing the line `NotebookFind[ButtonNotebook[],tag,All,CellTags]` with `NotebookLocate[tag]` seems to correct the issue in @Nasser's comment. Also, there is an extra term `tag` inside `Setter[Dynamic[CurrentValue[....] ...` that needs be deleted. – kglr Jan 17 '12 at 04:47
  • @kguler I think you mean `tag` inside `CurrentValue`, not in `Setter`. If you remove this, the Setter won't appear pressed until you actually press a button. It appears to be an undocumented third argument that provides a default value. – Szabolcs Jan 17 '12 at 13:22
  • @Szabolcs, yes, I mean the first of two consecutive `tag`s which gets highlighted as red by syntax highlighter. However, it works both with and without the first of the two consecutive tags. It is very unlikely to be a typo. – kglr Jan 17 '12 at 15:24
  • 1
    @kguler To clarify, in my previous comment I meant that the red `tag` is *necessary* for this to work correctly. Without it no setter will appear pressed initially, as the notebook is created. It should not be removed. – Szabolcs Jan 17 '12 at 15:33
  • @Szabolc, I agree, it is setting the first argument of `Setter` to `tag` which is needed for the setter to look pressed. – kglr Jan 17 '12 at 15:54
  • 1
    @Nasser, seems to be a bug in the FE. I've confirmed that `NotebookFind` is finding the correct cell, but the FE is just not properly scrolling in this case. I'll look into it. In the mean time, I'll change my answer above to use NotebookLocate, which is nicely advantageous because it's simpler anyway. – John Fultz Jan 30 '12 at 04:11
  • 1
    @Szabolcs, the third (undocumented) argument to CurrentValue will create and set the value if the value doesn't exist. It's a very convenient way to establish default values of CurrentValue selectors (of the sort documented in the TaggingRules documentation) without writing a bunch of messy code. – John Fultz Jan 30 '12 at 04:15