[vset VERSION 1.0]
[comment {-*- tcl -*- widgetPlus manpage}]
[manpage_begin widgetPlus n [vset VERSION]]
[moddesc   {Enhanced Entry, Spinbox, and Combobox Widgets with Undo/Redo and other useful features}]
[titledesc {Enhanced Entry, Spinbox, and Combobox Widgets with Undo/Redo and other useful features}]
[require Tcl 8.5]
[require Tk 8.5]
[require snit]
[require widgetPlus [opt [vset VERSION]]]
[description]

The [package widgetPlus] package adds new features to the widgets [syscmd [widget entry]], [syscmd [widget spinbox]], [syscmd [widget ttk::entry]], [syscmd [widget ttk::spinbox]], and [syscmd [widget ttk::combobox]].

[para]
The new features are Undo and Redo operations, a [const <<Selection>>] event, and for the [const Tk] (unthemed) widgets an [option -inactiveselectbackground] option, and some minor fixes to bindings.  The new facilities closely follow those of the [syscmd [widget text]] widget.

[para]
The revised [syscmd [widget entry]], [syscmd [widget spinbox]], [syscmd [widget ttk::entry]], [syscmd [widget ttk::spinbox]], and [syscmd [widget ttk::combobox]] widgets are created by the commands [cmd widgetPlus::entryPlus], [cmd widgetPlus::spinboxPlus], [cmd widgetPlus::ttkEntryPlus], [cmd widgetPlus::ttkSpinboxPlus], and [cmd widgetPlus::ttkComboboxPlus] respectively.

[para]
For example, the [cmd widgetPlus::entryPlus] widget is implemented as a [term Snit] [syscmd snit::widgetadaptor] that wraps a [package Tk] [syscmd [widget entry]] widget.  Its [syscmd {winfo class}] is [const Entry], and it uses a binding tag [const EntryPlus] that replaces the [const Entry] binding tag.  The other widgets are implemented in a similar way.

[para]
The package uses the namespace [namespace ::widgetPlus], which exports (only) the five commands defined below that begin with a lower-case letter ([cmd EnableBWidget] is not exported).  These commands can be imported into the global namespace, and for simplicity, descriptive text in this manual will henceforth omit the namespace qualifier.

[example {
namespace import ::widgetPlus::*
}]


[section {WIDGET OPTIONS}]

In addition to the usual options of the [syscmd [widget entry]], [syscmd [widget spinbox]], [syscmd [widget ttk::entry]], [syscmd [widget ttk::spinbox]], and [syscmd [widget ttk::combobox]] widgets, the wrappers [cmd [widget entryPlus]], [cmd [widget spinboxPlus]], [cmd [widget ttkEntryPlus]], [cmd [widget ttkSpinboxPlus]], and [cmd [widget ttkComboboxPlus]] provide the options below.

[list_begin tkoptions]

[comment {
[tkoption_def [option -autoseparators] autoSeparators AutoSeparators]
Boolean value, currently ignored (see [sectref {TO DO}]). Currently, an implicit autoseparator is added to the [term {undo stack}] for each call to a widget command (e.g. [cmd insert] or [cmd delete]) that changes the widget contents: these therefore separate the addition or removal of individual characters, except that [term cut] or [term paste] operations are discrete.

[para]
[emph SHOULD] specify a [term boolean] that says whether separators are automatically inserted in the [term {undo stack}]. Only meaningful when the [option -undo] option is [const true].
}]

[tkoption_def [option -inactiveselectbackground] inactiveSelectBackground Foreground]
Specifies the color to use for the selection when the window does not have the input [syscmd focus]. If empty, [const {{}}], then no selection is shown when the window does not have the [syscmd focus].  The [option -inactiveselectbackground] option has no effect on the [const Ttk] (themed) widgets [cmd [widget ttkEntryPlus]], [cmd [widget ttkSpinboxPlus]], and [cmd [widget ttkComboboxPlus]].

[tkoption_def [option -maxundo] maxUndo MaxUndo]
Specifies the maximum number of compound undo actions on the [term {undo stack}]. A zero or a negative value imply an unlimited [term {undo stack}].

[tkoption_def [option -undo] undo Undo]
Specifies a [term boolean] that says whether the undo mechanism is active or not.

[list_end]

[section COMMANDS]

[list_begin definitions]

[call [cmd widgetPlus::entryPlus] [opt [arg create]] [arg pathName]]

Create an [cmd [widget entryPlus]] widget; or convert an existing [widget entry] widget into an [cmd [widget entryPlus]].

[call [cmd widgetPlus::spinboxPlus] [opt [arg create]] [arg pathName]]

Create a [cmd [widget spinboxPlus]] widget; or convert an existing [widget spinbox] widget into a [cmd [widget spinboxPlus]].

[call [cmd widgetPlus::ttkEntryPlus] [opt [arg create]] [arg pathName]]

Create a [cmd [widget ttkEntryPlus]] widget; or convert an existing [widget ttk::entry] widget into a [cmd [widget ttkEntryPlus]].

[call [cmd widgetPlus::ttkSpinboxPlus] [opt [arg create]] [arg pathName]]

Create a [cmd [widget ttkSpinboxPlus]] widget; or convert an existing [widget ttk::spinbox] widget into a [cmd [widget ttkSpinboxPlus]].

[call [cmd widgetPlus::ttkComboboxPlus] [opt [arg create]] [arg pathName]]

Create a [cmd [widget ttkComboboxPlus]] widget; or convert an existing [widget ttk::combobox] widget into a [cmd [widget ttkComboboxPlus]].

[call [cmd widgetPlus::EnableBWidget]]

Enable [package widgetPlus] to modify [package BWidget] [syscmd [widget Entry]] widgets and their compounds (such as the [package BWidget] [syscmd [widget ComboBox]]).  The command creates a bindtag [const BwEntryPlus] to replace the default bindtag [const BwEntry].  This operation is not performed when the package is loaded because it requires [package BWidget] to be loaded first.  This command is not exported from namespace [namespace ::widgetPlus].


[list_end]

[section {WIDGET COMMANDS}]

In addition to the usual commands of the [syscmd [widget entry]], [syscmd [widget spinbox]], [syscmd [widget ttk::entry]], [syscmd [widget ttk::spinbox]], and [syscmd [widget ttk::combobox]] widgets, the wrappers [cmd [widget entryPlus]], [cmd [widget ttkEntryPlus]], [cmd [widget spinboxPlus]], [cmd [widget ttkSpinboxPlus]], and [cmd [widget ttkComboboxPlus]] provide:

[list_begin definitions]

[call [arg pathName] [cmd edit] [opt [arg {arg arg ...}]]]
    This command controls the undo mechanism and the [term {modified flag}]. The exact behavior of the command depends on the option argument that follows the edit argument. The following forms of the command are currently supported:

[call [arg pathName] [cmd {edit canredo}]]
        Returns a [term boolean] [const true] if redo is possible, i.e. when the [term {redo stack}] is not empty. Otherwise returns [const false].

[call [arg pathName] [cmd {edit canundo}]]
        Returns a [term boolean] [const true] if undo is possible, i.e. when the [term {undo stack}] is not empty. Otherwise returns [const false].

[call [arg pathName] [cmd {edit modified}] [opt [arg boolean]]]
        If [arg boolean] is not specified, returns the [term {modified flag}] of the widget. The [cmd insert], [cmd delete], [cmd {edit undo}] and [cmd {edit redo}] commands, or (by using this command) the user, can set or clear the [term {modified flag}]. If [arg boolean] is specified, sets the [term {modified flag}] of the widget to [arg boolean].

[call [arg pathName] [cmd {edit redo}]]
        When the [option -undo] option is [const true], reapplies the last undone edits provided no other edits were done since then. Generates an error when the [term {redo stack}] is empty. Does nothing when the [option -undo] option is [const false].

[call [arg pathName] [cmd {edit reset}]]
        Clears the [term {undo stack}] and [term {redo stack}].

[call [arg pathName] [cmd {edit separator}]]
        Included for completeness, but has no effect.

        [para]

        (N.B. An implicit separator is added to the [term {undo stack}] for each call to a widget command (e.g. [cmd insert] or [cmd delete]) that changes the widget contents.  These therefore separate the addition or removal of individual characters by typing, except that [term cut] or [term paste] operations are discrete.)
[comment { from text(n)
        Inserts a separator (boundary) on the [term {undo stack}]. Does nothing when the [option -undo] option is [const false].
}]

[call [arg pathName] [cmd {edit undo}]]
        Undoes the last edit action when the [option -undo] option is [const true]. An edit action is defined as a single [cmd insert] or [cmd delete] command that is recorded on the [term {undo stack}]. Generates an error when the [term {undo stack}] is empty. Does nothing when the [option -undo] option is [const false].
[comment { from text(n)
        Undoes the last edit action when the [option -undo] option is [const true]. An edit action is defined as all the [cmd insert] and [cmd delete] commands that are recorded on the [term {undo stack}] in between two separators. Generates an error when the [term {undo stack}] is empty. Does nothing when the [option -undo] option is [const false].
}]

[list_end]

[section BINDINGS]
[subsection {Class Bindings}]

The class binding tag for different widgets has these default values:

[list_begin itemized]

[item] [syscmd [widget entry]]           uses [const Entry]
[item] [syscmd [widget spinbox]]         uses [const Spinbox]
[item] [syscmd [widget ttk::entry]]      uses [const TEntry]
[item] [syscmd [widget ttk::spinbox]]    uses [const TSpinbox]
[item] [syscmd [widget ttk::combobox]]   uses [const TCombobox]
[item]    [cmd [widget entryPlus]]       uses [const EntryPlus]
[item]    [cmd [widget spinboxPlus]]     uses [const SpinboxPlus]
[item]    [cmd [widget ttkEntryPlus]]    uses [const TEntryPlus]
[item]    [cmd [widget ttkSpinboxPlus]]  uses [const TSpinboxPlus]
[item]    [cmd [widget ttkComboboxPlus]] uses [const TComboboxPlus]

[list_end]

[subsection {Undo and Redo}]

The [const <<Undo>>] and [const <<Redo>>] virtual events are mapped to these keyboard events:

[list_begin itemized]

[item] On X11 systems (Linux[subst \u00ae], BSD[subst \u00ae], Solaris[subst \u00ae], etc):
[list_begin itemized][item][const <<Undo>>] is mapped to [const <Control-z>][list_end]
[list_begin itemized][item][const <<Redo>>] is mapped to [const <Control-Shift-z>][list_end]

[item] On Windows[subst \u00ae] systems:
[list_begin itemized][item][const <<Undo>>] is mapped to [const <Control-z>][list_end]
[list_begin itemized][item][const <<Redo>>] is mapped to [const <Control-y>][list_end]

[item] On Aqua[subst \u00ae] systems (i.e. Apple[subst \u00ae] macOS[subst \u00ae] or OS X[subst \u00ae]):
[list_begin itemized][item][const <<Undo>>] is mapped to [const <Command-z>][list_end]
[list_begin itemized][item][const <<Redo>>] is mapped to [const <Command-Shift-z>][list_end]

[list_end]


[subsection EntryPlus]

The [const EntryPlus] bindings are based on those of the [const Entry] bindtag, with these changes:

[list_begin itemized]

[item] New bindings to [const <<Undo>>] and [const <<Redo>>].

[item] An adjustment to the [const <<Paste>>] binding, so that it behaves the same way on X11 as on other windowing systems (i.e. it deletes the existing selection, if any exists).

[item] The removal of the antiquated [const <Insert>] binding.

[item] New bindings to [const <FocusIn>] and [const <FocusOut>], to facilitate the implementation of the [option -inactiveselectbackground] option.

[list_end]

[subsection SpinboxPlus]

The [const SpinboxPlus] bindings are based on those of the [const Spinbox] bindtag, with the same changes as are made when converting [const Entry] to [const EntryPlus].

[subsection TEntryPlus]

The [const TEntryPlus] bindings are based on those of the [const TEntry] bindtag, with these changes:

[list_begin itemized]

[item] New bindings to [const <<Undo>>] and [const <<Redo>>].

[list_end]

[subsection TSpinboxPlus]

The [const TSpinboxPlus] bindings are based on those of the [const TSpinbox] bindtag, with these changes:

[list_begin itemized]

[item] New bindings to [const <<Undo>>] and [const <<Redo>>].

[list_end]

[subsection TComboboxPlus]

The [const TComboboxPlus] bindings are based on those of the [const TCombobox] bindtag, with these changes:

[list_begin itemized]

[item] New bindings to [const <<Undo>>] and [const <<Redo>>].

[list_end]


[section {VIRTUAL EVENT <<Selection>>}]

Each [package widgetPlus] widget generates a virtual event [const <<Selection>>] whenever the value of its selection changes.  This allows other [package Tcl] code, for example the package [package persistentSelection], to monitor the selection in these widgets.

[section {USE WITH MEGAWIDGETS}]

When an [syscmd [widget entry]], [syscmd [widget spinbox]], [syscmd [widget ttk::entry]], [syscmd [widget ttk::spinbox]], or [syscmd [widget ttk::combobox]] is a component of a megawidget, it is often possible to apply [package widgetPlus] to that component without modifying the megawidget code.

[subsection {combobox (by Bryan Oakley)}]

A [syscmd [widget combobox]] with path [const {$w}] includes an [syscmd [widget entry]] widget [const {$w.entry}], which uses the [const Entry] binding tag.  Thus [package widgetPlus] can be applied to the [syscmd [widget combobox]] after creation, using the command (see [sectref EXAMPLES])

[example {
entryPlus $w.entry -undo 1 -maxundo 0
}]

[subsection {ComboBox (BWidget)}]

A [package BWidget] [syscmd ComboBox] with path [const {$w}] includes an [syscmd [widget entry]] widget [const {$w.e}], which uses the [const BwEntry] binding tag in place of the default tag [const Entry].

[para]
Package [package widgetPlus] provides a replacement bindtag [const BwEntryPlus], but this is not computed when the package is loaded because it requires [package BWidget] to be loaded first.  The command [cmd ::widgetPlus::EnableBWidget] must be called to provide [const BwEntryPlus], and then the [package BWidget] [syscmd ComboBox] can be modified (see [sectref EXAMPLES])

[example {
::widgetPlus::EnableBWidget
entryPlus $w.e -undo 1 -maxundo 0
}]



[section {TO DO}]

[list_begin itemized]

[item] Undo and Redo do not sync the value of the [term {modified flag}] - they always set the value to [term boolean] [const true].
[item] Undo and Redo do not sync the position of the insertion cursor.
[item] The [const <<Modified>>] event is not generated.
[item] Undo/Redo separators, and the [option -autoseparators] option, as found in the [syscmd [widget text]] widget, are not implemented. An implicit separator is added for each call to a widget command (e.g. [cmd insert] or [cmd delete]) that changes the widget contents.  The [cmd {edit separator}] command has no effect.  Separator functionality would be less useful for widgets such as [cmd [widget entryPlus]] than it is for a [syscmd [widget text]] widget.
[item] Add an [term overwrite] mode, toggled by [const <Insert>] on non-macOS[subst \u00ae] systems.

[list_end]

[section BUGS]

This version of [package widgetPlus] is intended to be compatible with all releases of [package Tk] 8.5 and 8.6, and with the branches [emph core-8-5-branch], [emph core-8-6-branch], and [emph trunk] in the source code repository for [package Tk].  Any incompatibility with any of these versions, for any [package Tk] windowing system, should be reported as a bug. Please report such in the category [emph widgetPlus] of the [uri http://core.tcl.tk/tklib/reportlist {Tklib Trackers}].

[section EXAMPLES]

To create and map an [cmd [widget entryPlus]] widget .ep with an unlimited Undo/Redo stack:
[example {
package require widgetPlus
widgetPlus::entryPlus .ep -undo 1 -maxundo 0
pack .ep
}]

The same but using [syscmd {namespace import}]:
[example {
package require widgetPlus
namespace import widgetPlus::*
entryPlus .ep -undo 1 -maxundo 0
pack .ep
}]

To convert an existing [syscmd [widget entry]] widget .ee into an [cmd [widget entryPlus]] with an unlimited Undo/Redo stack:
[example {
entry .ee

    .
    .
    .

package require widgetPlus
widgetPlus::entryPlus .ee -undo 1 -maxundo 0
}]

The same but using [syscmd {namespace import}]:
[example {
entry .ee

    .
    .
    .

package require widgetPlus
namespace import widgetPlus::*
entryPlus .ee -undo 1 -maxundo 0
}]

Apply [package widgetPlus] to a Bryan Oakley [syscmd [widget combobox]]:
[example {
package require combobox
combobox::combobox .cb

    .
    .
    .

package require widgetPlus
namespace import widgetPlus::*
entryPlus .cb.entry -undo 1 -maxundo 0
}]

Apply [package widgetPlus] to a [package BWidget] [syscmd [widget ComboBox]].  The command [cmd ::widgetPlus::EnableBWidget] must be called first.
[example {
package require BWidget
ComboBox .cb

    .
    .
    .

package require widgetPlus
::widgetPlus::EnableBWidget
namespace import widgetPlus::*

entryPlus .cb.e -undo 1 -maxundo 0
}]

[see_also entry spinbox ttk::entry ttk::spinbox ttk::combobox]
[see_also text persistentSelection BWidget ComboBox Entry]

[vset CATEGORY widgetPlus]
[include ../../support/devel/doc/feedback.inc]
[manpage_end]
