static
char
sccsid[] =
"@(#) tkTextMark.c 1.11 95/06/28 10:42:39"
;
#include "tkInt.h"
#include "tkText.h"
#include "tkPort.h"
#define MSEG_SIZE ((unsigned) (Tk_Offset(TkTextSegment, body) \
+
sizeof
(TkTextMark)))
static
void
InsertUndisplayProc _ANSI_ARGS_((TkText *textPtr,
TkTextDispChunk *chunkPtr));
static
int
MarkDeleteProc _ANSI_ARGS_((TkTextSegment *segPtr,
TkTextLine *linePtr,
int
treeGone));
static
TkTextSegment * MarkCleanupProc _ANSI_ARGS_((TkTextSegment *segPtr,
TkTextLine *linePtr));
static
void
MarkCheckProc _ANSI_ARGS_((TkTextSegment *segPtr,
TkTextLine *linePtr));
static
int
MarkLayoutProc _ANSI_ARGS_((TkText *textPtr,
TkTextIndex *indexPtr, TkTextSegment *segPtr,
int
offset,
int
maxX,
int
maxChars,
int
noCharsYet, Tk_Uid wrapMode,
TkTextDispChunk *chunkPtr));
Tk_SegType tkTextRightMarkType = {
"mark"
,
0,
(Tk_SegSplitProc *) NULL,
MarkDeleteProc,
MarkCleanupProc,
(Tk_SegLineChangeProc *) NULL,
MarkLayoutProc,
MarkCheckProc
};
Tk_SegType tkTextLeftMarkType = {
"mark"
,
1,
(Tk_SegSplitProc *) NULL,
MarkDeleteProc,
MarkCleanupProc,
(Tk_SegLineChangeProc *) NULL,
MarkLayoutProc,
MarkCheckProc
};
int
TkTextMarkCmd(textPtr, interp, argc, args)
register
TkText *textPtr;
Tcl_Interp *interp;
int
argc;
Arg *args;
{
int
c, i;
size_t
length;
Tcl_HashEntry *hPtr;
TkTextSegment *markPtr;
Tcl_HashSearch search;
TkTextIndex index;
Tk_SegType *newTypePtr;
if
(argc < 3) {
Tcl_AppendResult(interp,
"wrong # args: should be \""
,
LangString(args[0]),
" mark option ?arg arg ...?\""
, NULL);
return
TCL_ERROR;
}
c = LangString(args[2])[0];
length =
strlen
(LangString(args[2]));
if
((c ==
'g'
) && (
strncmp
(LangString(args[2]),
"gravity"
, length) == 0)) {
if
(argc > 5) {
Tcl_AppendResult(interp,
"wrong # args: should be \""
,
LangString(args[0]),
" mark gravity markName ?gravity?"
,
NULL);
return
TCL_ERROR;
}
hPtr = Tcl_FindHashEntry(&textPtr->markTable, LangString(args[3]));
if
(hPtr == NULL) {
Tcl_AppendResult(interp,
"there is no mark named \""
,
LangString(args[3]),
"\""
, NULL);
return
TCL_ERROR;
}
markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
if
(argc == 4) {
if
(markPtr->typePtr == &tkTextRightMarkType) {
Tcl_SetResult(interp,
"right"
,TCL_STATIC);
}
else
{
Tcl_SetResult(interp,
"left"
,TCL_STATIC);
}
return
TCL_OK;
}
length =
strlen
(LangString(args[4]));
c = LangString(args[4])[0];
if
((c ==
'l'
) && (
strncmp
(LangString(args[4]),
"left"
, length) == 0)) {
newTypePtr = &tkTextLeftMarkType;
}
else
if
((c ==
'r'
) && (
strncmp
(LangString(args[4]),
"right"
, length) == 0)) {
newTypePtr = &tkTextRightMarkType;
}
else
{
Tcl_AppendResult(interp,
"bad mark gravity \""
,
LangString(args[4]),
"\": must be left or right"
, NULL);
return
TCL_ERROR;
}
TkTextMarkSegToIndex(textPtr, markPtr, &index);
TkBTreeUnlinkSegment(textPtr->tree, markPtr,
markPtr->body.mark.linePtr);
markPtr->typePtr = newTypePtr;
TkBTreeLinkSegment(markPtr, &index);
}
else
if
((c ==
'n'
) && (
strncmp
(LangString(args[2]),
"names"
, length) == 0)) {
if
(argc != 3) {
Tcl_AppendResult(interp,
"wrong # args: should be \""
,
LangString(args[0]),
" mark names\""
, NULL);
return
TCL_ERROR;
}
for
(hPtr = Tcl_FirstHashEntry(&textPtr->markTable, &search);
hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
Tcl_AppendElement(interp,
Tcl_GetHashKey(&textPtr->markTable, hPtr));
}
}
else
if
((c ==
's'
) && (
strncmp
(LangString(args[2]),
"set"
, length) == 0)) {
if
(argc != 5) {
Tcl_AppendResult(interp,
"wrong # args: should be \""
,
LangString(args[0]),
" mark set markName index\""
, NULL);
return
TCL_ERROR;
}
if
(TkTextGetIndex(interp, textPtr, LangString(args[4]), &index) != TCL_OK) {
return
TCL_ERROR;
}
TkTextSetMark(textPtr, LangString(args[3]), &index);
}
else
if
((c ==
'u'
) && (
strncmp
(LangString(args[2]),
"unset"
, length) == 0)) {
for
(i = 3; i < argc; i++) {
hPtr = Tcl_FindHashEntry(&textPtr->markTable, LangString(args[i]));
if
(hPtr != NULL) {
markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
if
((markPtr == textPtr->insertMarkPtr)
|| (markPtr == textPtr->currentMarkPtr)) {
continue
;
}
TkBTreeUnlinkSegment(textPtr->tree, markPtr,
markPtr->body.mark.linePtr);
Tcl_DeleteHashEntry(hPtr);
ckfree((
char
*) markPtr);
}
}
}
else
{
Tcl_AppendResult(interp,
"bad mark option \""
, LangString(args[2]),
"\": must be gravity, names, set, or unset"
,
NULL);
return
TCL_ERROR;
}
return
TCL_OK;
}
TkTextSegment *
TkTextSetMark(textPtr, name, indexPtr)
TkText *textPtr;
char
*name;
TkTextIndex *indexPtr;
{
Tcl_HashEntry *hPtr;
TkTextSegment *markPtr;
TkTextIndex insertIndex;
int
new
;
hPtr = Tcl_CreateHashEntry(&textPtr->markTable, name, &
new
);
markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
if
(!
new
) {
if
(markPtr == textPtr->insertMarkPtr) {
TkTextIndex index, index2;
TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, &index);
TkTextIndexForwChars(&index, 1, &index2);
TkTextChanged(textPtr, &index, &index2);
if
(TkBTreeLineIndex(indexPtr->linePtr)
== TkBTreeNumLines(textPtr->tree)) {
TkTextIndexBackChars(indexPtr, 1, &insertIndex);
indexPtr = &insertIndex;
}
}
TkBTreeUnlinkSegment(textPtr->tree, markPtr,
markPtr->body.mark.linePtr);
}
else
{
markPtr = (TkTextSegment *) ckalloc(MSEG_SIZE);
markPtr->typePtr = &tkTextRightMarkType;
markPtr->size = 0;
markPtr->body.mark.textPtr = textPtr;
markPtr->body.mark.linePtr = indexPtr->linePtr;
markPtr->body.mark.hPtr = hPtr;
Tcl_SetHashValue(hPtr, markPtr);
}
TkBTreeLinkSegment(markPtr, indexPtr);
if
(markPtr == textPtr->insertMarkPtr) {
TkTextIndex index2;
TkTextIndexForwChars(indexPtr, 1, &index2);
TkTextChanged(textPtr, indexPtr, &index2);
}
return
markPtr;
}
void
TkTextMarkSegToIndex(textPtr, markPtr, indexPtr)
TkText *textPtr;
TkTextSegment *markPtr;
TkTextIndex *indexPtr;
{
TkTextSegment *segPtr;
indexPtr->tree = textPtr->tree;
indexPtr->linePtr = markPtr->body.mark.linePtr;
indexPtr->charIndex = 0;
for
(segPtr = indexPtr->linePtr->segPtr; segPtr != markPtr;
segPtr = segPtr->nextPtr) {
indexPtr->charIndex += segPtr->size;
}
}
int
TkTextMarkNameToIndex(textPtr, name, indexPtr)
TkText *textPtr;
char
*name;
TkTextIndex *indexPtr;
{
Tcl_HashEntry *hPtr;
hPtr = Tcl_FindHashEntry(&textPtr->markTable, name);
if
(hPtr == NULL) {
return
TCL_ERROR;
}
TkTextMarkSegToIndex(textPtr, (TkTextSegment *) Tcl_GetHashValue(hPtr),
indexPtr);
return
TCL_OK;
}
static
int
MarkDeleteProc(segPtr, linePtr, treeGone)
TkTextSegment *segPtr;
TkTextLine *linePtr;
int
treeGone;
{
return
1;
}
static
TkTextSegment *
MarkCleanupProc(markPtr, linePtr)
TkTextSegment *markPtr;
TkTextLine *linePtr;
{
markPtr->body.mark.linePtr = linePtr;
return
markPtr;
}
static
int
MarkLayoutProc(textPtr, indexPtr, segPtr, offset, maxX, maxChars,
noCharsYet, wrapMode, chunkPtr)
TkText *textPtr;
TkTextIndex *indexPtr;
TkTextSegment *segPtr;
int
offset;
int
maxX;
int
maxChars;
int
noCharsYet;
Tk_Uid wrapMode;
register
TkTextDispChunk *chunkPtr;
{
if
(segPtr != textPtr->insertMarkPtr) {
return
-1;
}
chunkPtr->displayProc = TkTextInsertDisplayProc;
chunkPtr->undisplayProc = InsertUndisplayProc;
chunkPtr->measureProc = (Tk_ChunkMeasureProc *) NULL;
chunkPtr->bboxProc = (Tk_ChunkBboxProc *) NULL;
chunkPtr->numChars = 0;
chunkPtr->minAscent = 0;
chunkPtr->minDescent = 0;
chunkPtr->minHeight = 0;
chunkPtr->width = 0;
chunkPtr->breakIndex = -1;
chunkPtr->clientData = (ClientData) textPtr;
return
1;
}
void
TkTextInsertDisplayProc(chunkPtr, x, y, height, baseline, display, dst, screenY)
TkTextDispChunk *chunkPtr;
int
x;
int
y;
int
height;
int
baseline;
Display *display;
Drawable dst;
int
screenY;
{
TkText *textPtr = (TkText *) chunkPtr->clientData;
int
halfWidth = textPtr->insertWidth/2;
if
((x + halfWidth) <= 0) {
return
;
}
if
(textPtr->flags & INSERT_ON) {
Tk_Fill3DRectangle(textPtr->tkwin, dst, textPtr->insertBorder,
x - textPtr->insertWidth/2, y, textPtr->insertWidth,
height, textPtr->insertBorderWidth, TK_RELIEF_RAISED);
}
else
if
(textPtr->selBorder == textPtr->insertBorder) {
Tk_Fill3DRectangle(textPtr->tkwin, dst, textPtr->border,
x - textPtr->insertWidth/2, y, textPtr->insertWidth,
height, 0, TK_RELIEF_FLAT);
}
}
static
void
InsertUndisplayProc(textPtr, chunkPtr)
TkText *textPtr;
TkTextDispChunk *chunkPtr;
{
return
;
}
static
void
MarkCheckProc(markPtr, linePtr)
TkTextSegment *markPtr;
TkTextLine *linePtr;
{
Tcl_HashSearch search;
Tcl_HashEntry *hPtr;
if
(markPtr->body.mark.linePtr != linePtr) {
panic(
"MarkCheckProc: markPtr->body.mark.linePtr bogus"
);
}
for
(hPtr = Tcl_FirstHashEntry(&markPtr->body.mark.textPtr->markTable,
&search); hPtr != markPtr->body.mark.hPtr;
hPtr = Tcl_NextHashEntry(&search)) {
if
(hPtr == NULL) {
panic(
"MarkCheckProc couldn't find hash table entry for mark"
);
}
}
}