OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tkTextMark.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tkTextMark.c --
3
 *
4
 *      This file contains the procedure that implement marks for
5
 *      text widgets.
6
 *
7
 * Copyright (c) 1994 The Regents of the University of California.
8
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
9
 *
10
 * See the file "license.terms" for information on usage and redistribution
11
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12
 *
13
 * RCS: @(#) $Id: tkTextMark.c,v 1.1.1.1 2002-01-16 10:25:53 markom Exp $
14
 */
15
 
16
#include "tkInt.h"
17
#include "tkText.h"
18
#include "tkPort.h"
19
 
20
/*
21
 * Macro that determines the size of a mark segment:
22
 */
23
 
24
#define MSEG_SIZE ((unsigned) (Tk_Offset(TkTextSegment, body) \
25
        + sizeof(TkTextMark)))
26
 
27
/*
28
 * Forward references for procedures defined in this file:
29
 */
30
 
31
static void             InsertUndisplayProc _ANSI_ARGS_((TkText *textPtr,
32
                            TkTextDispChunk *chunkPtr));
33
static int              MarkDeleteProc _ANSI_ARGS_((TkTextSegment *segPtr,
34
                            TkTextLine *linePtr, int treeGone));
35
static TkTextSegment *  MarkCleanupProc _ANSI_ARGS_((TkTextSegment *segPtr,
36
                            TkTextLine *linePtr));
37
static void             MarkCheckProc _ANSI_ARGS_((TkTextSegment *segPtr,
38
                            TkTextLine *linePtr));
39
static int              MarkLayoutProc _ANSI_ARGS_((TkText *textPtr,
40
                            TkTextIndex *indexPtr, TkTextSegment *segPtr,
41
                            int offset, int maxX, int maxChars,
42
                            int noCharsYet, Tk_Uid wrapMode,
43
                            TkTextDispChunk *chunkPtr));
44
static int              MarkFindNext _ANSI_ARGS_((Tcl_Interp *interp,
45
                            TkText *textPtr, char *markName));
46
static int              MarkFindPrev _ANSI_ARGS_((Tcl_Interp *interp,
47
                            TkText *textPtr, char *markName));
48
 
49
 
50
/*
51
 * The following structures declare the "mark" segment types.
52
 * There are actually two types for marks, one with left gravity
53
 * and one with right gravity.  They are identical except for
54
 * their gravity property.
55
 */
56
 
57
Tk_SegType tkTextRightMarkType = {
58
    "mark",                                     /* name */
59
    0,                                           /* leftGravity */
60
    (Tk_SegSplitProc *) NULL,                   /* splitProc */
61
    MarkDeleteProc,                             /* deleteProc */
62
    MarkCleanupProc,                            /* cleanupProc */
63
    (Tk_SegLineChangeProc *) NULL,              /* lineChangeProc */
64
    MarkLayoutProc,                             /* layoutProc */
65
    MarkCheckProc                               /* checkProc */
66
};
67
 
68
Tk_SegType tkTextLeftMarkType = {
69
    "mark",                                     /* name */
70
    1,                                          /* leftGravity */
71
    (Tk_SegSplitProc *) NULL,                   /* splitProc */
72
    MarkDeleteProc,                             /* deleteProc */
73
    MarkCleanupProc,                            /* cleanupProc */
74
    (Tk_SegLineChangeProc *) NULL,              /* lineChangeProc */
75
    MarkLayoutProc,                             /* layoutProc */
76
    MarkCheckProc                               /* checkProc */
77
};
78
 
79
/*
80
 *--------------------------------------------------------------
81
 *
82
 * TkTextMarkCmd --
83
 *
84
 *      This procedure is invoked to process the "mark" options of
85
 *      the widget command for text widgets. See the user documentation
86
 *      for details on what it does.
87
 *
88
 * Results:
89
 *      A standard Tcl result.
90
 *
91
 * Side effects:
92
 *      See the user documentation.
93
 *
94
 *--------------------------------------------------------------
95
 */
96
 
97
int
98
TkTextMarkCmd(textPtr, interp, argc, argv)
99
    register TkText *textPtr;   /* Information about text widget. */
100
    Tcl_Interp *interp;         /* Current interpreter. */
101
    int argc;                   /* Number of arguments. */
102
    char **argv;                /* Argument strings.  Someone else has already
103
                                 * parsed this command enough to know that
104
                                 * argv[1] is "mark". */
105
{
106
    int c, i;
107
    size_t length;
108
    Tcl_HashEntry *hPtr;
109
    TkTextSegment *markPtr;
110
    Tcl_HashSearch search;
111
    TkTextIndex index;
112
    Tk_SegType *newTypePtr;
113
 
114
    if (argc < 3) {
115
        Tcl_AppendResult(interp, "wrong # args: should be \"",
116
                argv[0], " mark option ?arg arg ...?\"", (char *) NULL);
117
        return TCL_ERROR;
118
    }
119
    c = argv[2][0];
120
    length = strlen(argv[2]);
121
    if ((c == 'g') && (strncmp(argv[2], "gravity", length) == 0)) {
122
        if (argc < 4 || argc > 5) {
123
            Tcl_AppendResult(interp, "wrong # args: should be \"",
124
                    argv[0], " mark gravity markName ?gravity?\"",
125
                    (char *) NULL);
126
            return TCL_ERROR;
127
        }
128
        hPtr = Tcl_FindHashEntry(&textPtr->markTable, argv[3]);
129
        if (hPtr == NULL) {
130
            Tcl_AppendResult(interp, "there is no mark named \"",
131
                    argv[3], "\"", (char *) NULL);
132
            return TCL_ERROR;
133
        }
134
        markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
135
        if (argc == 4) {
136
            if (markPtr->typePtr == &tkTextRightMarkType) {
137
                interp->result = "right";
138
            } else {
139
                interp->result = "left";
140
            }
141
            return TCL_OK;
142
        }
143
        length = strlen(argv[4]);
144
        c = argv[4][0];
145
        if ((c == 'l') && (strncmp(argv[4], "left", length) == 0)) {
146
            newTypePtr = &tkTextLeftMarkType;
147
        } else if ((c == 'r') && (strncmp(argv[4], "right", length) == 0)) {
148
            newTypePtr = &tkTextRightMarkType;
149
        } else {
150
            Tcl_AppendResult(interp, "bad mark gravity \"",
151
                    argv[4], "\": must be left or right", (char *) NULL);
152
            return TCL_ERROR;
153
        }
154
        TkTextMarkSegToIndex(textPtr, markPtr, &index);
155
        TkBTreeUnlinkSegment(textPtr->tree, markPtr,
156
                markPtr->body.mark.linePtr);
157
        markPtr->typePtr = newTypePtr;
158
        TkBTreeLinkSegment(markPtr, &index);
159
    } else if ((c == 'n') && (strncmp(argv[2], "names", length) == 0)) {
160
        if (argc != 3) {
161
            Tcl_AppendResult(interp, "wrong # args: should be \"",
162
                    argv[0], " mark names\"", (char *) NULL);
163
            return TCL_ERROR;
164
        }
165
        for (hPtr = Tcl_FirstHashEntry(&textPtr->markTable, &search);
166
                hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
167
            Tcl_AppendElement(interp,
168
                    Tcl_GetHashKey(&textPtr->markTable, hPtr));
169
        }
170
    } else if ((c == 'n') && (strncmp(argv[2], "next", length) == 0)) {
171
        if (argc != 4) {
172
            Tcl_AppendResult(interp, "wrong # args: should be \"",
173
                    argv[0], " mark next index\"", (char *) NULL);
174
            return TCL_ERROR;
175
        }
176
        return MarkFindNext(interp, textPtr, argv[3]);
177
    } else if ((c == 'p') && (strncmp(argv[2], "previous", length) == 0)) {
178
        if (argc != 4) {
179
            Tcl_AppendResult(interp, "wrong # args: should be \"",
180
                    argv[0], " mark previous index\"", (char *) NULL);
181
            return TCL_ERROR;
182
        }
183
        return MarkFindPrev(interp, textPtr, argv[3]);
184
    } else if ((c == 's') && (strncmp(argv[2], "set", length) == 0)) {
185
        if (argc != 5) {
186
            Tcl_AppendResult(interp, "wrong # args: should be \"",
187
                    argv[0], " mark set markName index\"", (char *) NULL);
188
            return TCL_ERROR;
189
        }
190
        if (TkTextGetIndex(interp, textPtr, argv[4], &index) != TCL_OK) {
191
            return TCL_ERROR;
192
        }
193
        TkTextSetMark(textPtr, argv[3], &index);
194
    } else if ((c == 'u') && (strncmp(argv[2], "unset", length) == 0)) {
195
        for (i = 3; i < argc; i++) {
196
            hPtr = Tcl_FindHashEntry(&textPtr->markTable, argv[i]);
197
            if (hPtr != NULL) {
198
                markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
199
                if ((markPtr == textPtr->insertMarkPtr)
200
                        || (markPtr == textPtr->currentMarkPtr)) {
201
                    continue;
202
                }
203
                TkBTreeUnlinkSegment(textPtr->tree, markPtr,
204
                        markPtr->body.mark.linePtr);
205
                Tcl_DeleteHashEntry(hPtr);
206
                ckfree((char *) markPtr);
207
            }
208
        }
209
    } else {
210
        Tcl_AppendResult(interp, "bad mark option \"", argv[2],
211
                "\": must be gravity, names, next, previous, set, or unset",
212
                (char *) NULL);
213
        return TCL_ERROR;
214
    }
215
    return TCL_OK;
216
}
217
 
218
/*
219
 *----------------------------------------------------------------------
220
 *
221
 * TkTextSetMark --
222
 *
223
 *      Set a mark to a particular position, creating a new mark if
224
 *      one doesn't already exist.
225
 *
226
 * Results:
227
 *      The return value is a pointer to the mark that was just set.
228
 *
229
 * Side effects:
230
 *      A new mark is created, or an existing mark is moved.
231
 *
232
 *----------------------------------------------------------------------
233
 */
234
 
235
TkTextSegment *
236
TkTextSetMark(textPtr, name, indexPtr)
237
    TkText *textPtr;            /* Text widget in which to create mark. */
238
    char *name;                 /* Name of mark to set. */
239
    TkTextIndex *indexPtr;      /* Where to set mark. */
240
{
241
    Tcl_HashEntry *hPtr;
242
    TkTextSegment *markPtr;
243
    TkTextIndex insertIndex;
244
    int new;
245
 
246
    hPtr = Tcl_CreateHashEntry(&textPtr->markTable, name, &new);
247
    markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
248
    if (!new) {
249
        /*
250
         * If this is the insertion point that's being moved, be sure
251
         * to force a display update at the old position.  Also, don't
252
         * let the insertion cursor be after the final newline of the
253
         * file.
254
         */
255
 
256
        if (markPtr == textPtr->insertMarkPtr) {
257
            TkTextIndex index, index2;
258
            TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, &index);
259
            TkTextIndexForwChars(&index, 1, &index2);
260
            TkTextChanged(textPtr, &index, &index2);
261
            if (TkBTreeLineIndex(indexPtr->linePtr)
262
                    == TkBTreeNumLines(textPtr->tree))  {
263
                TkTextIndexBackChars(indexPtr, 1, &insertIndex);
264
                indexPtr = &insertIndex;
265
            }
266
        }
267
        TkBTreeUnlinkSegment(textPtr->tree, markPtr,
268
                markPtr->body.mark.linePtr);
269
    } else {
270
        markPtr = (TkTextSegment *) ckalloc(MSEG_SIZE);
271
        markPtr->typePtr = &tkTextRightMarkType;
272
        markPtr->size = 0;
273
        markPtr->body.mark.textPtr = textPtr;
274
        markPtr->body.mark.linePtr = indexPtr->linePtr;
275
        markPtr->body.mark.hPtr = hPtr;
276
        Tcl_SetHashValue(hPtr, markPtr);
277
    }
278
    TkBTreeLinkSegment(markPtr, indexPtr);
279
 
280
    /*
281
     * If the mark is the insertion cursor, then update the screen at the
282
     * mark's new location.
283
     */
284
 
285
    if (markPtr == textPtr->insertMarkPtr) {
286
        TkTextIndex index2;
287
 
288
        TkTextIndexForwChars(indexPtr, 1, &index2);
289
        TkTextChanged(textPtr, indexPtr, &index2);
290
    }
291
    return markPtr;
292
}
293
 
294
/*
295
 *--------------------------------------------------------------
296
 *
297
 * TkTextMarkSegToIndex --
298
 *
299
 *      Given a segment that is a mark, create an index that
300
 *      refers to the next text character (or other text segment
301
 *      with non-zero size) after the mark.
302
 *
303
 * Results:
304
 *      *IndexPtr is filled in with index information.
305
 *
306
 * Side effects:
307
 *      None.
308
 *
309
 *--------------------------------------------------------------
310
 */
311
 
312
void
313
TkTextMarkSegToIndex(textPtr, markPtr, indexPtr)
314
    TkText *textPtr;            /* Text widget containing mark. */
315
    TkTextSegment *markPtr;     /* Mark segment. */
316
    TkTextIndex *indexPtr;      /* Index information gets stored here.  */
317
{
318
    TkTextSegment *segPtr;
319
 
320
    indexPtr->tree = textPtr->tree;
321
    indexPtr->linePtr = markPtr->body.mark.linePtr;
322
    indexPtr->charIndex = 0;
323
    for (segPtr = indexPtr->linePtr->segPtr; segPtr != markPtr;
324
            segPtr = segPtr->nextPtr) {
325
        indexPtr->charIndex += segPtr->size;
326
    }
327
}
328
 
329
/*
330
 *--------------------------------------------------------------
331
 *
332
 * TkTextMarkNameToIndex --
333
 *
334
 *      Given the name of a mark, return an index corresponding
335
 *      to the mark name.
336
 *
337
 * Results:
338
 *      The return value is TCL_OK if "name" exists as a mark in
339
 *      the text widget.  In this case *indexPtr is filled in with
340
 *      the next segment whose after the mark whose size is
341
 *      non-zero.  TCL_ERROR is returned if the mark doesn't exist
342
 *      in the text widget.
343
 *
344
 * Side effects:
345
 *      None.
346
 *
347
 *--------------------------------------------------------------
348
 */
349
 
350
int
351
TkTextMarkNameToIndex(textPtr, name, indexPtr)
352
    TkText *textPtr;            /* Text widget containing mark. */
353
    char *name;                 /* Name of mark. */
354
    TkTextIndex *indexPtr;      /* Index information gets stored here. */
355
{
356
    Tcl_HashEntry *hPtr;
357
 
358
    hPtr = Tcl_FindHashEntry(&textPtr->markTable, name);
359
    if (hPtr == NULL) {
360
        return TCL_ERROR;
361
    }
362
    TkTextMarkSegToIndex(textPtr, (TkTextSegment *) Tcl_GetHashValue(hPtr),
363
            indexPtr);
364
    return TCL_OK;
365
}
366
 
367
/*
368
 *--------------------------------------------------------------
369
 *
370
 * MarkDeleteProc --
371
 *
372
 *      This procedure is invoked by the text B-tree code whenever
373
 *      a mark lies in a range of characters being deleted.
374
 *
375
 * Results:
376
 *      Returns 1 to indicate that deletion has been rejected.
377
 *
378
 * Side effects:
379
 *      None (even if the whole tree is being deleted we don't
380
 *      free up the mark;  it will be done elsewhere).
381
 *
382
 *--------------------------------------------------------------
383
 */
384
 
385
        /* ARGSUSED */
386
static int
387
MarkDeleteProc(segPtr, linePtr, treeGone)
388
    TkTextSegment *segPtr;              /* Segment being deleted. */
389
    TkTextLine *linePtr;                /* Line containing segment. */
390
    int treeGone;                       /* Non-zero means the entire tree is
391
                                         * being deleted, so everything must
392
                                         * get cleaned up. */
393
{
394
    return 1;
395
}
396
 
397
/*
398
 *--------------------------------------------------------------
399
 *
400
 * MarkCleanupProc --
401
 *
402
 *      This procedure is invoked by the B-tree code whenever a
403
 *      mark segment is moved from one line to another.
404
 *
405
 * Results:
406
 *      None.
407
 *
408
 * Side effects:
409
 *      The linePtr field of the segment gets updated.
410
 *
411
 *--------------------------------------------------------------
412
 */
413
 
414
static TkTextSegment *
415
MarkCleanupProc(markPtr, linePtr)
416
    TkTextSegment *markPtr;             /* Mark segment that's being moved. */
417
    TkTextLine *linePtr;                /* Line that now contains segment. */
418
{
419
    markPtr->body.mark.linePtr = linePtr;
420
    return markPtr;
421
}
422
 
423
/*
424
 *--------------------------------------------------------------
425
 *
426
 * MarkLayoutProc --
427
 *
428
 *      This procedure is the "layoutProc" for mark segments.
429
 *
430
 * Results:
431
 *      If the mark isn't the insertion cursor then the return
432
 *      value is -1 to indicate that this segment shouldn't be
433
 *      displayed.  If the mark is the insertion character then
434
 *      1 is returned and the chunkPtr structure is filled in.
435
 *
436
 * Side effects:
437
 *      None, except for filling in chunkPtr.
438
 *
439
 *--------------------------------------------------------------
440
 */
441
 
442
        /*ARGSUSED*/
443
static int
444
MarkLayoutProc(textPtr, indexPtr, segPtr, offset, maxX, maxChars,
445
        noCharsYet, wrapMode, chunkPtr)
446
    TkText *textPtr;            /* Text widget being layed out. */
447
    TkTextIndex *indexPtr;      /* Identifies first character in chunk. */
448
    TkTextSegment *segPtr;      /* Segment corresponding to indexPtr. */
449
    int offset;                 /* Offset within segPtr corresponding to
450
                                 * indexPtr (always 0). */
451
    int maxX;                   /* Chunk must not occupy pixels at this
452
                                 * position or higher. */
453
    int maxChars;               /* Chunk must not include more than this
454
                                 * many characters. */
455
    int noCharsYet;             /* Non-zero means no characters have been
456
                                 * assigned to this line yet. */
457
    Tk_Uid wrapMode;            /* Not used. */
458
    register TkTextDispChunk *chunkPtr;
459
                                /* Structure to fill in with information
460
                                 * about this chunk.  The x field has already
461
                                 * been set by the caller. */
462
{
463
    if (segPtr != textPtr->insertMarkPtr) {
464
        return -1;
465
    }
466
 
467
    chunkPtr->displayProc = TkTextInsertDisplayProc;
468
    chunkPtr->undisplayProc = InsertUndisplayProc;
469
    chunkPtr->measureProc = (Tk_ChunkMeasureProc *) NULL;
470
    chunkPtr->bboxProc = (Tk_ChunkBboxProc *) NULL;
471
    chunkPtr->numChars = 0;
472
    chunkPtr->minAscent = 0;
473
    chunkPtr->minDescent = 0;
474
    chunkPtr->minHeight = 0;
475
    chunkPtr->width = 0;
476
 
477
    /*
478
     * Note: can't break a line after the insertion cursor:  this
479
     * prevents the insertion cursor from being stranded at the end
480
     * of a line.
481
     */
482
 
483
    chunkPtr->breakIndex = -1;
484
    chunkPtr->clientData = (ClientData) textPtr;
485
    return 1;
486
}
487
 
488
/*
489
 *--------------------------------------------------------------
490
 *
491
 * TkTextInsertDisplayProc --
492
 *
493
 *      This procedure is called to display the insertion
494
 *      cursor.
495
 *
496
 * Results:
497
 *      None.
498
 *
499
 * Side effects:
500
 *      Graphics are drawn.
501
 *
502
 *--------------------------------------------------------------
503
 */
504
 
505
        /* ARGSUSED */
506
void
507
TkTextInsertDisplayProc(chunkPtr, x, y, height, baseline, display, dst, screenY)
508
    TkTextDispChunk *chunkPtr;          /* Chunk that is to be drawn. */
509
    int x;                              /* X-position in dst at which to
510
                                         * draw this chunk (may differ from
511
                                         * the x-position in the chunk because
512
                                         * of scrolling). */
513
    int y;                              /* Y-position at which to draw this
514
                                         * chunk in dst (x-position is in
515
                                         * the chunk itself). */
516
    int height;                         /* Total height of line. */
517
    int baseline;                       /* Offset of baseline from y. */
518
    Display *display;                   /* Display to use for drawing. */
519
    Drawable dst;                       /* Pixmap or window in which to draw
520
                                         * chunk. */
521
    int screenY;                        /* Y-coordinate in text window that
522
                                         * corresponds to y. */
523
{
524
    TkText *textPtr = (TkText *) chunkPtr->clientData;
525
    int halfWidth = textPtr->insertWidth/2;
526
 
527
    if ((x + halfWidth) < 0) {
528
        /*
529
         * The insertion cursor is off-screen.  Just return.
530
         */
531
 
532
        return;
533
    }
534
 
535
    /*
536
     * As a special hack to keep the cursor visible on mono displays
537
     * (or anywhere else that the selection and insertion cursors
538
     * have the same color) write the default background in the cursor
539
     * area (instead of nothing) when the cursor isn't on.  Otherwise
540
     * the selection might hide the cursor.
541
     */
542
 
543
    if (textPtr->flags & INSERT_ON) {
544
        Tk_Fill3DRectangle(textPtr->tkwin, dst, textPtr->insertBorder,
545
                x - textPtr->insertWidth/2, y, textPtr->insertWidth,
546
                height, textPtr->insertBorderWidth, TK_RELIEF_RAISED);
547
    } else if (textPtr->selBorder == textPtr->insertBorder) {
548
        Tk_Fill3DRectangle(textPtr->tkwin, dst, textPtr->border,
549
                x - textPtr->insertWidth/2, y, textPtr->insertWidth,
550
                height, 0, TK_RELIEF_FLAT);
551
    }
552
}
553
 
554
/*
555
 *--------------------------------------------------------------
556
 *
557
 * InsertUndisplayProc --
558
 *
559
 *      This procedure is called when the insertion cursor is no
560
 *      longer at a visible point on the display.  It does nothing
561
 *      right now.
562
 *
563
 * Results:
564
 *      None.
565
 *
566
 * Side effects:
567
 *      None.
568
 *
569
 *--------------------------------------------------------------
570
 */
571
 
572
        /* ARGSUSED */
573
static void
574
InsertUndisplayProc(textPtr, chunkPtr)
575
    TkText *textPtr;                    /* Overall information about text
576
                                         * widget. */
577
    TkTextDispChunk *chunkPtr;          /* Chunk that is about to be freed. */
578
{
579
    return;
580
}
581
 
582
/*
583
 *--------------------------------------------------------------
584
 *
585
 * MarkCheckProc --
586
 *
587
 *      This procedure is invoked by the B-tree code to perform
588
 *      consistency checks on mark segments.
589
 *
590
 * Results:
591
 *      None.
592
 *
593
 * Side effects:
594
 *      The procedure panics if it detects anything wrong with
595
 *      the mark.
596
 *
597
 *--------------------------------------------------------------
598
 */
599
 
600
static void
601
MarkCheckProc(markPtr, linePtr)
602
    TkTextSegment *markPtr;             /* Segment to check. */
603
    TkTextLine *linePtr;                /* Line containing segment. */
604
{
605
    Tcl_HashSearch search;
606
    Tcl_HashEntry *hPtr;
607
 
608
    if (markPtr->body.mark.linePtr != linePtr) {
609
        panic("MarkCheckProc: markPtr->body.mark.linePtr bogus");
610
    }
611
 
612
    /*
613
     * Make sure that the mark is still present in the text's mark
614
     * hash table.
615
     */
616
 
617
    for (hPtr = Tcl_FirstHashEntry(&markPtr->body.mark.textPtr->markTable,
618
            &search); hPtr != markPtr->body.mark.hPtr;
619
            hPtr = Tcl_NextHashEntry(&search)) {
620
        if (hPtr == NULL) {
621
            panic("MarkCheckProc couldn't find hash table entry for mark");
622
        }
623
    }
624
}
625
 
626
/*
627
 *--------------------------------------------------------------
628
 *
629
 * MarkFindNext --
630
 *
631
 *      This procedure searches forward for the next mark.
632
 *
633
 * Results:
634
 *      A standard Tcl result, which is a mark name or an empty string.
635
 *
636
 * Side effects:
637
 *      None.
638
 *
639
 *--------------------------------------------------------------
640
 */
641
 
642
static int
643
MarkFindNext(interp, textPtr, string)
644
    Tcl_Interp *interp;                 /* For error reporting */
645
    TkText *textPtr;                    /* The widget */
646
    char *string;                       /* The starting index or mark name */
647
{
648
    TkTextIndex index;
649
    Tcl_HashEntry *hPtr;
650
    register TkTextSegment *segPtr;
651
    int offset;
652
 
653
 
654
    hPtr = Tcl_FindHashEntry(&textPtr->markTable, string);
655
    if (hPtr != NULL) {
656
        /*
657
         * If given a mark name, return the next mark in the list of
658
         * segments, even if it happens to be at the same character position.
659
         */
660
        segPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
661
        TkTextMarkSegToIndex(textPtr, segPtr, &index);
662
        segPtr = segPtr->nextPtr;
663
    } else {
664
        /*
665
         * For non-mark name indices we want to return any marks that
666
         * are right at the index.
667
         */
668
        if (TkTextGetIndex(interp, textPtr, string, &index) != TCL_OK) {
669
            return TCL_ERROR;
670
        }
671
        for (offset = 0, segPtr = index.linePtr->segPtr;
672
                segPtr != NULL && offset < index.charIndex;
673
                offset += segPtr->size, segPtr = segPtr->nextPtr) {
674
            /* Empty loop body */ ;
675
        }
676
    }
677
    while (1) {
678
        /*
679
         * segPtr points at the first possible candidate,
680
         * or NULL if we ran off the end of the line.
681
         */
682
        for ( ; segPtr != NULL ; segPtr = segPtr->nextPtr) {
683
            if (segPtr->typePtr == &tkTextRightMarkType ||
684
                    segPtr->typePtr == &tkTextLeftMarkType) {
685
                Tcl_SetResult(interp,
686
                    Tcl_GetHashKey(&textPtr->markTable, segPtr->body.mark.hPtr),
687
                    TCL_STATIC);
688
                return TCL_OK;
689
            }
690
        }
691
        index.linePtr = TkBTreeNextLine(index.linePtr);
692
        if (index.linePtr == (TkTextLine *) NULL) {
693
            return TCL_OK;
694
        }
695
        index.charIndex = 0;
696
        segPtr = index.linePtr->segPtr;
697
    }
698
}
699
 
700
/*
701
 *--------------------------------------------------------------
702
 *
703
 * MarkFindPrev --
704
 *
705
 *      This procedure searches backwards for the previous mark.
706
 *
707
 * Results:
708
 *      A standard Tcl result, which is a mark name or an empty string.
709
 *
710
 * Side effects:
711
 *      None.
712
 *
713
 *--------------------------------------------------------------
714
 */
715
 
716
static int
717
MarkFindPrev(interp, textPtr, string)
718
    Tcl_Interp *interp;                 /* For error reporting */
719
    TkText *textPtr;                    /* The widget */
720
    char *string;                       /* The starting index or mark name */
721
{
722
    TkTextIndex index;
723
    Tcl_HashEntry *hPtr;
724
    register TkTextSegment *segPtr, *seg2Ptr, *prevPtr;
725
    int offset;
726
 
727
 
728
    hPtr = Tcl_FindHashEntry(&textPtr->markTable, string);
729
    if (hPtr != NULL) {
730
        /*
731
         * If given a mark name, return the previous mark in the list of
732
         * segments, even if it happens to be at the same character position.
733
         */
734
        segPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
735
        TkTextMarkSegToIndex(textPtr, segPtr, &index);
736
    } else {
737
        /*
738
         * For non-mark name indices we do not return any marks that
739
         * are right at the index.
740
         */
741
        if (TkTextGetIndex(interp, textPtr, string, &index) != TCL_OK) {
742
            return TCL_ERROR;
743
        }
744
        for (offset = 0, segPtr = index.linePtr->segPtr;
745
                segPtr != NULL && offset < index.charIndex;
746
                offset += segPtr->size, segPtr = segPtr->nextPtr) {
747
            /* Empty loop body */ ;
748
        }
749
    }
750
    while (1) {
751
        /*
752
         * segPtr points just past the first possible candidate,
753
         * or at the begining of the line.
754
         */
755
        for (prevPtr = NULL, seg2Ptr = index.linePtr->segPtr;
756
                seg2Ptr != NULL && seg2Ptr != segPtr;
757
                seg2Ptr = seg2Ptr->nextPtr) {
758
            if (seg2Ptr->typePtr == &tkTextRightMarkType ||
759
                    seg2Ptr->typePtr == &tkTextLeftMarkType) {
760
                prevPtr = seg2Ptr;
761
            }
762
        }
763
        if (prevPtr != NULL) {
764
            Tcl_SetResult(interp,
765
                Tcl_GetHashKey(&textPtr->markTable, prevPtr->body.mark.hPtr),
766
                TCL_STATIC);
767
            return TCL_OK;
768
        }
769
        index.linePtr = TkBTreePreviousLine(index.linePtr);
770
        if (index.linePtr == (TkTextLine *) NULL) {
771
            return TCL_OK;
772
        }
773
        segPtr = NULL;
774
    }
775
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.