/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tktextmark.c
ViewVC logotype

Contents of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tktextmark.c

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25