TIP #446: Introspect Undo/Redo Stack Depths
_____________________________________________________________________________
TIP:	446
Title:	Introspect Undo/Redo Stack Depths
Version:	$Revision: 1.9 $
Authors:	François Vogel <fvogelnew1@free.fr>
State:	Final
Type:	Project
Tcl-Version:	8.6.6
Vote:	Done
Created:	Tue Apr 05 00:00:00 UTC 2016
Keywords:	Tk
Abstract
Tk features a generic undo/redo mechanism (see [104]). This is used in practice by the text widget, within the edit command. The present TIP proposes to add two new subcommands to the edit command allowing the user to know whether undo and redo is possible for a text widget.
Rationale
The undo/redo feature of Tk is handy and works very well. In modern GUIs, there is usually a button in a menubar to call the "Undo" command, and likewise for "Redo". It is good practice to enhance the user experience by greying out or otherwise changing the button aspect when there is nothing to undo (or redo). This cannot be achieved currently with the curent Tk implementation because there is no way to know whether the undo and redo stacks are empty or not.
This feature was requested for the text widget in RFE 1273358 [https://core.tcl.tk/tk/tktview/1273358]
Proposed Change
It is proposed to add the following subcommands to the text widget's edit command:
canundo:
Returns a boolean true if undo is possible, i.e. when the undo stack is not empty. Otherwise returns false.
canredo:
Returns a boolean true if redo is possible, i.e. when the undo stack is not empty. Otherwise returns false.
When the -undo option of the text widget is false both subcommands return false since indeed no undo nor redo action is possible in this case. The undo/redo stacks are however not cleared, so that when -undo becomes eventually true again the two new subcommands will return their value in accordance with the contents of the stacks (this is current behavior of the undo/redo feature - the TIP does not intend to change this).
This new capability will be implemented in the generic code for undo (generic/tkUndo.c), so that any client of the generic undo/redo mechanism can make use of it. Currently, only the text widget is concerned since no other Tk widget is featuring undo/redo.
Besides the two new subcommands, it is also proposed to add a new virtual event <<UndoStack>>, that will trigger each time the undo or redo stack becomes empty or unempty. When this condition is met, the event will trigger once for each peer widget.
Despite this is a new feature, this TIP targets Tk 8.6.6 since no change of any existing behavior is proposed: only new, additonal, features are proposed. It is therefore believed there is no risk regarding backwards compatibility in the 8.6.x series.
Example
  package require Tk

  pack [text .t -undo false -autoseparators false]

  set nbUS 0
  bind .t <<UndoStack>> incr nbUS

  .t edit canundo    ; # 0
  .t edit canredo    ; # 0

  .t configure -undo true

  .t edit canundo    ; # 0
  .t edit canredo    ; # 0

  .t insert end "ABC"
  .t edit separator
  .t insert end "DEF"
  .t insert end "DEF again"
  .t edit separator

  .t edit canundo    ; # 1
  .t edit canredo    ; # 0

  .t edit undo

  .t edit canundo    ; # 1
  .t edit canredo    ; # 1

  # A quick interactive testing environment...:
  
  pack [label .l]
  
  proc showit  
    global nbUS
    .l configure -text "Can undo: [.t edit canundo]\par                        Can redo: [.t edit canredo]\par                        <<UndoStack>> triggered: $nbUS"
    after 200 showit
  
  showit
  
  proc toggleautosep  
    global autosepset
    set autosepset [.t cget -autoseparators]
    if $autosepset 
      .t configure -autoseparators false
     else 
      .t configure -autoseparators true
    
    set autosepset [.t cget -autoseparators]
  
  proc toggleundo  
    global undoset
    set undoset [.t cget -undo]
    if $undoset 
      .t configure -undo false
     else 
      .t configure -undo true
    
    set undoset [.t cget -undo]
  
  button .b1 -text "Insert separator" -command .t edit separator
  button .b2 -text "Undo" -command .t edit undo
  button .b3 -text "Redo" -command .t edit redo
  button .b32 -text "Reset" -command .t edit reset
  checkbutton .b4 -text "-autoseparators" -command toggleautosep -variable autosepset
  checkbutton .b5 -text "-undo" -command toggleundo -variable undoset ; .b5 select
  
  pack .b1 .b2 .b3 .b32 .b4 .b5 -side left -padx 10
Reference Implementation
A reference implementation is available in branch tip-446 of the fossil repository. Credits for this implementation largely go to Neil Hodgson, the author of TkTextPlus (for canundo/canredo) and to Koen Danckaert (for <<UndoStack>>).
Copyright
This document has been placed in the public domain.
_____________________________________________________________________________
Colophon
TIP AutoGenerator - written by Donal K. Fellows