znotebook

ABU 29-oct-2023 - znotebook 1.1

ABU 10-Aug-2024 - znotebook 1.1.1 - now compatible with Tcl9

=== ZNOTEBOOK ================================================================
znotebook is an extension of the standard [ttk::notebook] widget.
 -- variation inspired by the scrollutil::scrollednotebook (by Csaba Nemethi)
==============================================================================

Image_notebookAnim1

A full app: see Highlighter 2.x : znotebook + pdfviewer Image_notebook2

  znotebook 1.1 Reference

znotebook 1.1 znotebook ttk::notebook extension

a ttk::notebook extension

SYNOPSIS

package require znotebook 1.1

  • znotebook pathName ?options?
  • pathName detachtab tabId ?title?
  • pathName rejoin w ?pos?
  • pathName rejoin all ?pos?
  • pathName dtabs
  • pathName attrib ?name ?value name value ...??
  • pathName hasattrib name
  • pathName unsetattrib name
  • pathName tabattrib tabW ?name ?value name value ...??
  • pathName hastabattrib tabW name
  • pathName unsetattrib tabW ?name?

DESCRIPTION

znotebook is an extension of the standard ttk::notebook widget. -- variation inspired by the scrollutil::scrollednotebook (by Csaba Nemethi)

All ttk::notebook's options and commands are supported. znotebook comes with new options for controlling its new interactive features.

  • All znotebook tabs can be interactively rearranged (Click and drag).
  • If a tab is dragged outside the tabs-area, it becomes a "detached tab", i.e. a new toplevel window.
  • Detached-tabs have a small special button (rejoin-button) to bring it back to the notebook.
  • All notebook tabs have a small [x] button for destroying the tab.
  • New options (-preclosetab and -postclosetab) can be used to control which tabs can be removed, and then for cleanup after the tab has been (interactively) removed.
  • Znotebook tabs can be renamed interactively.
  • Znotebook provides a default [+] button (wholly programmable) for adding new tabs.
  • Tooltips can be added with external packages.

See the included demo.tcl for a quick tour.

WIDGET OPTIONS

znotebook supports all ttk::notebook options plus the following

znotebook specific options

-renametab boolean
If boolean is "true" (or any equivalent boolean value), then tabs can be interactively renamed with a double-click on the tab. Editing ends when the user presses <Return>, <Escape>, or clicks outside the editing window. By default, it is set to false.
-showaddbutton boolean
When this option is set to true (or any equivalent boolean value), a small (+) button is placed to the left of the first tab. By default, it is set to false. This button should be programmed with the -addcommand option.
-addcommand cmdPrefix
Specifies the prefix of a Tcl command to invoke whenever the special close-tab (+) button is pressed. The actual command consists of this option concatenated with the pathname of the znotebook widget. It is responsibility of this command to create a (composite) widget (typically a frame with some sub-widgets), and then attach this new widget by issuing a standard "add" or "insert" command
    znotebook .nb1
    .nb1 configure -showaddbutton true -addcommad AddTab
    proc AddTab {nb} {
        set f [frame $nb.tab_[newID]]  ;#  [newID] should generate a new unique id ...
            ....
         .. populate $f with some sub-widget ....
        ....
         # ... if everything is OK ....
        $nb add $f -text "some text.."
    }
-preclosetabcommand cmdPrefix
Specifies the prefix of a Tcl command to be invoked when the close-tab button is pressed. The actual command consists of this option concatenated with the pathname of the znotebook widget and the pathname of the tab's related window. If the return value of this command is true then the tab is removed (i.e. the "forget" subcommand is automatically executed), and then the script related to the -postcloseclosetab option is executed.
-postclosetabcommand cmdPrefix
Specifies the prefix of a Tcl command to be invoked after a tab has been *interactively* removed. The actual command consists of this option concatenated with the pathname of the (removed) tab's related widgets. Note that when a tab is removed, its contents (the related widgets) are simply unmanaged; it is user's responsibility to destroy/release all the unmanaged resources.
     znotebook .nb2
    .nb2 configure  -preclosetabcommand  AskConfirm  -postclosetabcommand TabCleanupTab

    proc AskConfirm {nb w} {
           set x [tk_messageBox -type yesnocancel -message "Are you sure you want to close this tab \"$tabName\" ?"]
           return [expr {$x eq "yes" ? true : false}]
    }
    proc TabCleanup {w} {
        ...  release all the related resources ...
        destroy $w
    }

WIDGET COMMANDS

znotebook pathName ?options?
The znotebook command creates a new widget (given by the pathName argument). Additional options, described above, may be specified on the command line or in the option database to configure default aspects of the zoom-canvas. At the time this command is invoked, there must not exist a window named pathName, but pathNames parent must exist. The znotebook command returns its pathName argument. Once created, pathName may be used to invoke all the standard ttk::notebook' subcommands plus the following

znotebook specific commands

pathName detachtab tabId ?title?
detach the widget denoted by tabid from the notebook. The tab's content becomes a new toplevel widget with an added rejoin-button.

tabid is a multiform identifier: tab-index, slave-window, @x,y, "current or "end" The optional title specifies the title of the toplevel window (default is the same text of the label) This method returns the pathname of the new toplevel window or {} if tab cannot be detached. A tab cannot be detached in the following cases:

  • tab has the special attribute _detachable set to "false"
  • it cannot be transformed in a toplevel window (i.e. the tab's related widget is NOT a frame).
pathName rejoin w ?pos?
pathName rejoin all ?pos?
The first subcommand rejoins a detached-tab to its original notebook. An error is raised if w is not a detached-tab.

The second subcommand rejoins all the detached-tab. The optional pos denotes where to insert the rejoined tab among all the notebook's tabs. Default is end, i.e. rejoined tabs are inserted after the last notebook's tab.

pathName dtabs
List all the detached-tabs, similar to the standard tabs sub-command.
pathName attrib ?name ?value name value ...??
Queries or modifies the attributes of the widget.

If no name is specified, the command returns a list of pairs, each of which contains the name and the value of an attribute for pathName. If name is specified with no value, then the command returns the value of the named attribute, or an empty string if no corresponding value exists (you can use the hasattrib subcommand to distinguish this case from the one that the value of an existing attribute is an empty string). If one or more name-value pairs are specified, then the command sets the given widget attribute(s) to the given value(s); in this case the return value is an empty string. Each name may be an arbitrary string.

pathName hasattrib name
Returns 1 if the attribute name exists and 0 otherwise.
pathName unsetattrib name
Unsets the attribute name. Returns an empty string.
pathName tabattrib tabW ?name ?value name value ...??
Queries or modifies the attributes of a given tab. tabW is the tab's related slave-window. (see subcommands tab and dtabs).

If no name is specified, the command returns a list of pairs, each of which contains the name and the value of an attribute for the tab tabW. If name is specified with no value, then the command returns the value of the named attribute, or an empty string if no corresponding value exists (you can use the hastabattrib subcommand to distinguish this case from the one that the value of an existing attribute is an empty string). If one or more name-value pairs are specified, then the command sets the given tab attribute(s) to the given value(s); in this case, the return value is an empty string. Each name may be an arbitrary string.

pathName hastabattrib tabW name
Returns 1 if the tab tabW has attribute name, and 0 otherwise.
pathName unsetattrib tabW ?name?
If name is not specified, unsets all tabW attributes.

If name is specified, unsets the attribute name of tab tabW. (No error is returned if tabW is not a tab, or if tabW has no attribute name). Returns an empty string.

special attribute names

Please note that in general attributes and tab-attributes starting with _ (underscore) are reserved for special purposes. Currently znotebook provides the following tab-attributes:

_closable
If this special tab-attribute is set to "false" (or any other equivalent boolean value), then its close-button is disabled.
_detachable
If this special tab-attribute is set to "false" (or any other equivalent boolean value), then tab cannot be detached.

Extended BINDINGS

znotebooks handles the following additional bindings for the ttk::notebook:

Theme changes:
whenever a ttk:style theme is changed, znotebook adapts its style
Moving the tabs of a znotebook with the mouse:
if mouse button 1 is pressed over a tab but outside its close-button, and then dragged, then the tab is moved. If the tab is dragged above or below the tab-area, then the tab becomes a detached-tab. Exception of this rule is when a znotebook has just one tab, or when the selected tab has the special _detachable tab-attribute set to false
Closing a tab with the aid of the tab's close-button:
If mouse button 1 is pressed over the tab's close-button and the close-button is not disabled (see the above note for the _closable tab-attribute), then the command set with the -preclosetabcommand option is called. If this command returns true (or if this command is not defined), then the tab is closed and then the command set with the -postclosetabcommand is called.
Renaming a tab:
if the user double-clicks over a tab, then the tab can be interactively renamed. Editing ends when the user presses <Return>, <Escape>, or clicks outside the editing window.

Extended EVENTS

  • Virtual event <<Z.NotebookTabDetached>> is generated whenever a tab is detached.
  • Virtual event <<Z.NotebookTabRejoined>> is generated whenever a detached tab is rejoined to its notebook. These virtual-events carry some data that may be caught in binding script by the %d substitution keyword. Parameter %d holds the tab's path-name.

Examples

ttk::style theme clam   ;# any theme ..

package require znotebook

global TABNUM
set TABNUM 100

proc AddTab {nb} {
        global TABNUM
        incr TABNUM
        
        set f [frame $nb.f${TABNUM} -background yellow]
        # TODO: ... fill the frame with other sub-widgets ...
        $nb add $f -text "tab $TABNUM"
        $nb select $f
}

proc OnClosedTab {tabW} {
        destroy $tabW
}
          
znotebook .nb  -renametab true  -showaddbutton true  -addcommand AddTab  -postclosetabcommand OnClosedTab
pack .nb -expand 1 -fill both -padx 10 -pady 10

AddTab .nb
AddTab .nb

Limitations

  • Only horizontal tabs on top of the client area - no support for placing tabs on the bottom, left, or right side of the client area.
  • ttk::theme support is still rather incomplete. It will be subject to future developments.

BUGS, IDEAS, FEEDBACK

  • -
  • -

KEYWORDS

Snit, notebook, widget

CATEGORY

widgets

COPYRIGHT

 Copyright (c) 2023-2024, by A.Buratti

  Discussion

chw 2024-08-10: Nice work, Aldo! Can this be made into another variant similar on how Firefox deals with tabs and toplevels, i.e. in that the detach does not detach into an own singular toplevel but in one with tabs, too? And dragging tabs between two or more toplevels transfers the tab into the respective destination toplevel? And thus eliminating the need for the special re-attach button? Is this feasible?

ABU This could be a nice idea, but as far as I know it's impossible to do.

When a tab of notebook is created , it belongs to the toplevel's notebook. This tab (a frame..) can be detached and transformed in a stand alone top-level window, ( see "wm manage ..") but it cannot placed inside another toplevel other than its 'original' toplevel. Note that this is not a limitation of znotebook, nor a ttk:notebook limitation. The limitation is simply/deeply about how toplevels and frames works in Tk.

Thus tabs notebooks cannot be moved in another notebook.

chw 2024-08-12: Thanks for the explanation. Reading further in the Tk documentation, I believe it could maybe done, when frames with -container would be used in the notebook tabs to manage toplevels with the -use option. However, still needs an enhanced Tk allowing to change the -use option after widget creation, i.e. in the configure method of the toplevel.

Download

Download znotebook 1.1.1