\documentclass[]{article}
\usepackage{amsmath,graphicx,supertabular,hyperref,tabularx,ifthen}
\title{TIP \#446: Introspect Undo/Redo Stack Depths}
\date{April 05, 2016}
\author{François Vogel}
\urlstyle{sf}
\setlength{\parskip}{1ex}
\setlength{\parindent}{0pt}
\def\tipversion$#1${\texttt{\$#1\$}}
\def\tiplangle#1{\ensuremath{<}}
\def\tiprangle#1{\ensuremath{>}}
\def\tipbar#1{\ensuremath{|}}
\def\tipmail#1#2{\(\langle\){\small\expandafter\url{#1@#2}}\(\rangle\)}
\ifx\pdfoutput\undefined
\newcommand{\tipimage}[2]{\typeout{Make sure you download #1.eps}\ifthenelse{\lengthtest{0.8\textwidth>#2}\and\lengthtest{0pt<#2}}{\includegraphics{#1.eps}}{\includegraphics[width=0.8\textwidth]{#1.eps}}}
\newcommand{\tipxref}[1]{}
\newcommand{\tipxrefend}{}
\else
\newcommand{\tipimage}[2]{\typeout{Make sure you create #1.pdf}\ifthenelse{\lengthtest{0.8\textwidth>#2}\and\lengthtest{0pt<#2}}{\includegraphics{#1.pdf}}{\includegraphics[width=0.8\textwidth]{#1.pdf}}}
\pdfcatalog{/PageMode /UseOutlines}
\newcommand{\tipxref}[1]{\pdfannotlink attr {/C [0.5 0.5 1.0] /Border [0 0 1]} goto name {#1}}
\newcommand{\tipxrefend}{\pdfendlink}
\fi
\newenvironment{tipabstract}{\begin{abstract}}{\end{abstract}}
\begin{document}\maketitle
\begin{center}\begin{tabularx}{\linewidth}{|r@{: }X|}\hline
\textbf{TIP \#446}&\textbf{Introspect Undo/Redo Stack Depths}\\\hline
Author&

François Vogel \tipmail{fvogelnew1}{free.fr}
\\
Created&Tuesday, \(\text{5}^{\text{th}}\) April 2016\\
Type&Project\\
Tcl Version&\(8.6.6\)\\
State&Final\\
Vote&Done\\
Version&\tipversion$Revision: 1.9 $\\
Keywords&Tk\\
Post History&\\
\hline\end{tabularx}\end{center}
\thispagestyle{empty}\pagestyle{empty}
\begin{tipabstract}

Tk features a generic undo/redo mechanism (see \cite{tip104}). This is used in practice by the \textbf{text} widget, within the \textbf{edit} command. The present TIP proposes to add two new subcommands to the \textbf{edit} command allowing the user to know whether undo and redo is possible for a \textbf{text} widget.
\end{tipabstract}
\tableofcontents\setcounter{page}{0}\clearpage\pagestyle{plain}

\section{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 [\url{https://core.tcl.tk/tk/tktview/1273358}]

\section{Proposed Change}

It is proposed to add the following subcommands to the \textbf{text} widget's \textbf{edit} command:

\textbf{canundo}:

\begin{quote}
Returns a boolean true if undo is possible, i.e. when the undo stack is not empty. Otherwise returns false.
\end{quote}

\textbf{canredo}:

\begin{quote}
Returns a boolean true if redo is possible, i.e. when the undo stack is not empty. Otherwise returns false.
\end{quote}

When the \textbf{-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 (\textit{generic/tkUndo.c}), so that any client of the generic undo/redo mechanism can make use of it. Currently, only the \textbf{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 \textbf{\tiplangle{}\tiplangle{}UndoStack\tiprangle{}\tiprangle{}}, 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.

\section{Example}
\begingroup\small\begin{verbatim}
  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\n"
  .t edit separator
  .t insert end "DEF\n"
  .t insert end "DEF again\n"
  .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]\t\t\t \
                        Can redo: [.t edit canredo]\t\t\t \
                        <<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
\end{verbatim}
\endgroup

\section{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 \tiplangle{}\tiplangle{}UndoStack\tiprangle{}\tiprangle{}).

\section{Copyright}

This document has been placed in the public domain.

\section{Colophon}

\textit{TIP AutoGenerator --- written by Donal K. Fellows}
\begin{thebibliography}{TIP \#1}
\addcontentsline{toc}{section}{References}
\bibitem[TIP \#104]{tip104}
Ludwig Callewaert,
Larry W. Virden.,
\emph{Generalization of the Tk Undo Subsystem},
on-line at \url{http://purl.org/tcl/tip/104.html}
\end{thebibliography}
\end{document}
