An object is a real object in Perl, and a list with a first element being the class id in TCL (the rest being the contests, in what follows the first element of the rest is referenced as the first element of the object).
The particular elements of the list represent:
Tk::Text::String
, class id is S
.
Tk::Text::MarkLeft
with id L
, and Tk::Text::MarkRight
with
id R
.
Tk::Text::TagOn
with id T
, and Tk::Text::TagOff
with
id t
.
Tk::Text::EmbWin
with id W
.
The inter-leaf separators are dumped as on object of class
Tk::Text::BlockSeparator
, with id |
, the contents being the
``depth'' of the separator. Note that the minimal possible depth is 1
for separators between leaves of the same parent.
Tk::Text::Block
, the class id isB
.
Tk::Text::Empty
, the class id being E
. The contenst is the
list of the block name, and (optionally) instance data.
I
An empty block (without leaves) occupies 1 unit of the index space.
Note that a block (however complicated) always fits in one line of the
index space. In particular, the usual bindings for
An empty block looks like Note that a string representation of a block (however complicated)
always fits in one line.
If inserted text contains no newlines, it is added to the leaf of tree
the insertion point is in (i.e., at or after the start of, and before
the end of). If it contains newlines, then the resulting leaf is split
into several at the inserted newlines. All the new leaves have the
same parent node as the initial leaf. Registered callback will be
called on insertion of newlines (not implemented).
Details are subject to change.
A layout procedure takes a variable number of input arguments. The
first element
is a list containing the block name and widget name, (possibly with an
addition, say, if instance data is present in the block, it will be
the next element). The second element gives the horizontal offset of the start
of the block inside the ambient line (it can be different from the
absolute horizontal position if the block is inside some other
block). The remaining elements specify the tree structure of the block and the
layout details of the leaves. Any child of the root node of the tree
provides one argument of the function. All the arguments are lists,
and
There are three possible formats of the elements in this list. All
are lists of numbers (and should be of the form
The remaining elements of the list provide x and y offsets of
the upper-left corner inside the ambient block, width, total width,
height, and baseline of the block as a whole, or of a group of leaves,
or a leaf. If it describes a group of leaves, the leaves are laid out
as by default layout procedure. Width, height, and baseline
information is used for displaying background of the line.
If all the leaves are laid out, then this list describes an additional
element to draw if the first element is greater than 0, i.e. it is
considered a
Block ID
of an additional drawing element, and the
rest specifies the layout of this element. If it is 0, then this
element of the list is ignored exactly as in other cases.
Summary:
Setting the If If
In the latter case index1 and index2 should be outside of any
block, or properly inside the same block. The newlines (or,
correspondingly, interleaf separators of enclosing block) are
converted into interleaf separators of newly created block. This is
prohibited for empty blocks.
If bit All undocumented bits are reserved and should be 0.
Note that it is not enough to use a tag even for gray background,
since the border of the tag is inside the rectangle that contains the
letter, and to get a correct pedestal look we want the border to
surround the letter, not to be drawn outside of them.
In what follows we use TCL as the language for callback. Of course,
the resulting code will be much simpler in some other languages.
First, we create the 2 new additional elements to display:
(or we could use existing ones, if possible). The third row creates a
row in the text widget that is empty, and has tag ``backgr1''. This row
will show the background only, and we will use it to show the raised
background behind the block. The fourth row memorizes the id of this
additional line, and the fifth one returns the text in the widget to
its initial state. The line is not shown anymore, but the way to show
it is preserved in a safe place. The second element is created in the
same way.
Next, since we are satisfied with the way the leaves of the tree are
places on the screen (i.e., one under another), we do not want to be
concerned with internal structure of the block tree, so we ask the
widget to lie about internal structure of the tree:
Now the data given to
Now
We will not replace the width of the row, so mouse events could be
directed to outside of the block if clicked in the extended area. (In
fact they won't, since we will extend the size of the ambient block.)
Next we calculated widths of additonal rows,
and their height and baselines. All is prepared now to layout the rows:
Note that the same list $addrow1 is good for specifying the size of the
total block, since the first element of the list (that is $backgrId)
is ignored in the information for the whole block. Now we need to
move the real contents of the block 5 points to the right and down
with respect to the rectangle occupied by the
block, and return the calculated information:
Note that it is vital to put addrow2 after addrow1, since it should be
drawn after the addrow1 for it to appear to be on top of addrow1.
That's all! Now you can create a binding for insertion of empty block
into the widget (this binding supposes that
This binding moves the insertion point inside the block, so you are
ready to fill block with whatever information you need.
Sample code in the distribution of extended text widget
provides other examples of blocks: superSub, Fraction, and so on.
While it is possible to implement this kind of block using the same
types of blocks as in the previous section, we will need a lot of code
change in the bindings if we use this approach: a usual block takes at
least 2 positions in the index space, so it is possible to make an
insertion inside this block. Thus we either need correction of
keybindings that move the insertion point, or should correct the the
insertion code to check whether the insertion happens inside a block
of this type. If we do not do this, we need additional decision how to
handle blocks of this type that have not-empty contents.
The solution is to use ``empty'' blocks that take only 1 position in the
index space, so it is impossible to insert text inside them. We make
block type empty by using configuration option
Note the spaces in the name of layoutcmd: No quoting is performed
during the call, so
The only ``working'' row is the
Examples of blocks
Here we provide several examples on the internal structure of blocks
that can implement the following objects. To see how the internal
structure (does not) correlate with the visual appearance, see
Display of blocks
.
Indices in blocks
A block occupies the following place in the index space: 1 index unit
for the start of the block, then all the leaves separated by 1 index
separators, and 1 index for the end of the block. Thus a block with
one empty leaf occupies 2 index units.
up
and down
will move you out of a block. (You should expect it, since leaves of a
block may be placed one under another, but may be not.)
String representation of blocks
The commands that convert block contents to string (.t get
,
selection and search) see the contents of a block as a string of the
same size as the size of block in the index space. The start of the
block looks like {
, end like }
, interleaf separators like |
.
.
.
Insertion in blocks
Insertion changes contents of the block if the insertion point is
inside the block, i.e.,
after starting index of the block and before the ending position (and
not inside some other block contained in the given one). Note that it
is impossible to be inside an empty block.
Destruction of blocks
When the block is destructed, it contents is merged into the
surrounding environment. Block's head and tail disappear, interleaf
separators behave like newlines. I.e., if block was contained in
another block, interleaf separators of deceased block became interleaf
separators of the parent block, otherwise they became line separators
in the text widget.
Deletion of text in blocks
Tags and blocks
Characters inside leaves can be tagged in the usual way. Interleaf
separators and tail of the block behave like end-of-lines when
tagged. The behaviour of tags on the start of block is undefined.
Bounding boxes
Bounding box for anything invisible is of size 0 and at theupper-left corner of the block.
Display of blocks
The display of blocks is completely customizable. It is based on the
current configuration of the
type
of displayed block.
Layout callback
Layout callback is the main component of the block.
Summary:
y
offset inside the block, width, I
The return value of the callback must be a list. The length of thelist (counting multiplicities, see below) must be at least the number of
leaves plus one. The first element of the list specifies the layout
information on the block as a whole, the others specify layout
information for the leaves and (possibly) additional elements to show.
{dd ... dd}
)
of lengths 1, 7, or 13. The first number is either repeat count, or
id of additional line to show (i.e., the same data as returned by
textWidget block addline index
command). Lists of different length have
the following meaning:
The total width above is the width of the leaf including the spacereserved for showing the background of the leaf terminator.
None of the returned date is used for clipping. However, it is used indirecting the mouse events and reporting bounding boxes.
{ig ig ig w ig h b}
{rc xo yo w tw h b}
{rc}
{bi xo yo w tw h b}
w
is not very important), put after leaves.
Lying to layout callback
It is possible to configure a block to lie about its structure to the
layout callback. This can greatly simplify writing the callback in
interpreted languages, if the default layout procedure is satisfactory for
parts of a block.
-layoutdepth
and/or -layoutwidths
options for a block
forces the layout procedure to be called with agruments corresponding
to modified tree structure.
-layoutdepth
is set, the depth of the tree is modified to be the
given number. If the true depth of the tree is too small, tree is
extended from the root side, if it too deep, the subtrees on the
maximal allowed depth level are mocked as lines with repeat count.
-layoutwidths
is set, this can restrict the number of branches
going out of any node of the modified tree. The value of this option
should be a list, elements of this list are either numbers, or lists
of the form {min max}
. (A single number
is equivalent to a pair
{number number}
). N-th element of the list controls the number of
branches going out of nodes on the distance N from the root. If there
are too few branches, it adds branches that contain simulated groups
of leaves with repeat count 0. If there are too many branches, it
groups several last brunches into one with appropriate I-layoutdepth
if the depth of the node is less
than -layoutdepth
.)>
Block subcommands
{}
.
index
.
Additional text widget options
-getFlags
1
is set, the string representation of a text range
always gives a string of the same length as the length of the
interval in the index space. If some text annotation results in an
empty string in the standard representation, it is represented as an
appropriate number of *
s if this bit is set. Currently this
concerns embedded windows only, which are represented as *
.
Minitutorial
Example of a simple ``pedestal'' block
Suppose you are satisfied with the standard layout procedure, but want
to extend the resulting group of lines 10 points to the right (so when
part of block is selected, selection extends 10 points to the
right of the rightmost element in leaves), and want to add a blue
3D background of width 5 with ``height'' 2 around the resulting guy,
and draw the block on gray 3D background of width 2.
myLayoutCmd
will be always the same, as if
the block consisted of one leaf only that is the direct child of the
root. So the arguments the myLayoutCmd
receives are the following
ones:
$c
, $w
, $tw
, $h
, $b
contain the count, width,
total width, height and baseline of the contents of the block.
Next we extend the total width of the row.
bindtags
are reverted):
Example of a simple ``tabulation'' block
Here we describe how to code blocks that contain no editable
information, but provide geometry management. Consider an example of
tabulation: if we implement tabulation as a block, the size of this
block should change depending on the position of the start, but the
only editing operation should be the deletion of the block as a whole.
-empty
:
5
and 35
become first two arguments of
layoutTab
procedure. This procedure can be as simple as follows:
set w
one. It calculates the width
of the block using the following rule:
The last row returns a list of length 2. The first element is thedescription of the block as a whole, the next one is necesssarily the
description of an additional element (since there are no ``regular''
leaves in the tree). This additional element is the same size as the
block itself, and is used only to provide some visual feedback. We use
id $backgrId2 created elsewhere (say, by the code in the previous
example), and ask for the rectangle to be 3 points above the baseline,
and 2 points below.
AUTHOR
Ilya Zakharevich <ilya@math.ohio-state.edu>
AVAILABILITY
L