Author: Brian Griffin <bgriffin@model.com>
Author: Vince Darley <vincentdarley@users.sourceforge.net>
State: Final
Type: Project
Vote: Done
Created: 28-Jan-2004
Post-History:
Tcl-Version: 8.5
Abstract
This TIP proposes adding a method to the text widget that will create peer text widgets, allowing two or more text widgets to share the same text, tags, and marks.
Rationale
One of the features offered by many text editors is the ability to split the view of text being edited. Currently editors based on the Tk text widget are required to create multiple widgets, duplicating all insert, delete, etc., operations on both widgets. The current text widget already separates almost all aspects of the data from the widget rendering and it would be a simple task to allow two (or more) widgets to share this data.
Proposed Change
The primary change is the addition of a 'peer' subcommand to any text widget, as follows:
$text peer create ...
$text peer names
The proposed implementation splits the widget structure into two pieces, sharable data and widget specific rendering parts. The text tree, tags (including their colours and fonts), marks, images, and undo stack would be placed in a reference counted, shared section, while the widget configuration options for tkwin, fonts, colors, bindings, etc., would remain with the widget. A method (peer create) is added that will create a new widget that will share the data with it's "parent." The shared data also contains a list of peers which is used to propagate widget updates when the data changes.
set widget [text .text]
set peer [$widget peer create .peer]
Once a peer is created it has all the rights and privileges of the creating parent. There is no restriction on the peer's window pathname. The creating parent may also be destroyed without affecting the peer; only when the last window (peer or parent) is destroyed will the data be deleted.
In keeping with Tcl's introspection nature, a "peer names" method is added that will return a list of peer widgets. This list does not include itself.
Lastly, all text widgets take two new configuration options to specify that the peer only shows a subset of the lines from the underling b-tree:
set peer [$widget peer create .peer -startline 53 -endline 125]
will create a peer which contains lines 53 to 125 of the underlying data store. The default is for a peer to contain the same range of lines as its 'parent', but one can use '-startline {} -endline {}' to force use of the entire b-tree.
Any peer widget can access a list of all other peers, via the 'peer names' command:
set peerlist [$widget peer names]
This list does not include $widget itself.
Detailed Description
All geometry/pixel-height information for peer widgets are calculated separately for each peer. This means each peer can have different height, width, scrollbar state, (even overall font size) with no problems.
The 'sel', 'insert', 'current' tag/marks are not shared. They are widget specific. Similarly the '-window' attribute of any embedded window is not shared, but widget specific (i.e. it can be configured separately for each peer). The '-create' option of an embedded window now supports % substitution of its script to allow multiple peers all to have embedded windows in a relatively easy fashion. '%W' is substituted by the embedding text widget pathname and '%%' by '%'. So, for example, the following test works nicely:
test textWind-17.6 {peer widget window configuration} {
catch {destroy .t .tt}
pack [text .t]
.t delete 1.0 end
.t insert 1.0 "Some sample text"
toplevel .tt
pack [.t peer create .tt.t]
.t window create 1.2 -create {frame %W.f -width 10 -height 20 -bg blue}
update ; update
set res [list [.t window configure 1.2 -window] \
[.tt.t window configure 1.2 -window]]
destroy .tt .t
set res
} {{-window {} {} {} .t.f} {-window {} {} {} .tt.t.f}}
All top-level text configuration options are widget-specific except those which involve the undo/redo/modified status of the widget, which are shared.
Further changes
It has been pointed out that some uses of the 'sel' tag in existing Tk-based editors require an additional tag for use when a given widget does not have the input focus (a 'background sel' tag), particularly on Windows/MacOS X where https://sourceforge.net/tracker/?func=detail&atid=112997&aid=1014213&group_id=12997 applies (selection is never shown in text widgets which don't have the focus). Such an approach would not work with peer widgets, because the 'background sel' tag would show up on all peers. This means the cited problem needs to be fixed, and we need programmatic control over the visualization of the "sel" tag in text widgets that don't have the focus. The proposed solution is the addition of a 'inactiveSelectionBackground' option to each text overall widget. This new text widget configuration option can take the {} value, in which case the selection is not shown when the widget is not active, or if it takes a value, then that is the colour to use for the inactive selection. This option is peer-widget-specific (and is effectively implemented by over-riding the 'sel' background colour if the widget doesn't have the focus; a minor modification to the current code on Win/MacOS which ignores 'sel' when the widget doesn't have the focus).
To Do
In the current patch (and in the original version of this TIP), bindings are not shared, but remain with the widget. Currently this includes tag bindings, but I think it would be better if tag bindings were shared (given that tags are shared). Unless anyone has a use-case showing why they should be independent, I'll update the implementation accordingly. Therefore shared tag bindings should be considered part of this TIP.
Alternatives
This does not preclude a future TIP from going further and making the B-tree data structure a fully-fledged Tcl structure (like an array or a dict or whatever), of which the text widget is just one example of a client. However, such issues are beyond the scope of this TIP (except to point out that the implementation is, by necessity, many steps in the same direction).
Reference Implementation
A reference implementation based on Tcl 8.5 is available at:
http://sourceforge.net/tracker/?func=detail&atid=312997&aid=994629&group\_id=12997
This includes new tests and documentation, and an update to one of the Text widget demos to show off the new functionality.
Incidentally, this patch also fixes the long-standing problem where renaming the text widget breaks the undo-stack (which used to record the actual widget name).
Copyright
This document has been placed in the public domain.