1 /* $XConsortium: Selection.c /main/22 1996/11/12 11:44:48 cde-hp $ */
2 /************************************<+>*************************************
3 ****************************************************************************
9 ** (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
11 ** (c) Copyright 1993, 1994 Hewlett-Packard Company
12 ** (c) Copyright 1993, 1994 International Business Machines Corp.
13 ** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
14 ** (c) Copyright 1993, 1994 Novell, Inc.
17 ****************************************************************************
18 ************************************<+>*************************************/
27 * Canvas Engine includes
30 #include "CanvasSegP.h"
36 #include "CvStringI.h"
37 #include "LayoutUtilI.h"
38 #include "SelectionI.h"
43 /******** Private Function Declarations ********/
44 static void AdjustSelection (
45 _DtCanvasStruct *canvas,
46 _DtCvSelectData next);
47 static int GetSelectedText(
48 _DtCanvasStruct *canvas,
49 _DtCvSelectData start,
52 _DtCvPointer *ret_data);
53 /******** End Private Function Declarations ********/
55 /******** Private Defines ********/
57 /******** End Private Defines ********/
59 /******** Macros ********/
60 #define Equal(a,b) (a.y == b.y && a.x == b.x)
61 #define LessThan(a,b) ((a.y < b.y) || (a.y == b.y && a.x < b.x))
62 #define GreaterThan(a,b) ((a.y > b.y) || (a.y == b.y && a.x > b.x))
63 #define LessThanEq(a,b) (Equal(a,b) || LessThan(a,b))
64 #define GreaterThanEq(a,b) (Equal(a,b) || GreaterThan(a,b))
66 #define InRegion(top,bot,min,max) ((min) <= (bot) && (top) <= (max))
68 /******** End Macros ********/
70 /******** Private Variable Declarations ********/
71 static const _DtCvSelectData defaultSelect = { -1, -1, -1, -1};
73 /******** End Private Variable Declarations ********/
75 /******************************************************************************
77 ******************************************************************************/
78 /******************************************************************************
79 * Function: StartXOfLine
81 * Purpose: Determine the start of a line, takes into consideration
82 * the traversal and link before values. The 'x' returned is
83 * exactly where the text/graphic is to be placed on the canvas.
84 *****************************************************************************/
87 _DtCanvasStruct *canvas,
90 _DtCvValue lastLinkVisible = FALSE;
95 xPos = _DtCvGetStartXOfLine(&line, &pSeg);
96 return (_DtCvAdvanceXOfLine( canvas, pSeg, xPos,
97 &lnkInd, &lastLinkVisible));
99 } /* End StartXOfLine */
101 /*****************************************************************************
102 * Function: SearchForClosestLine
104 * Purpose: Initializes the 'new' structure with information indicating
105 * what line is closest to the target_y.
106 * next->y Set to target_y if no line straddles it.
107 * Otherwise, it will be set to the minimum
108 * y of all lines straddling the target_y.
109 * next->x Set to target_x if no line straddles
110 * target_y or if target_x is before the
111 * first line straddling target_y.
112 * next->line_idx Set to -1 if no line straddles target_y.
113 * Otherwise, set to the first line that
114 * straddles target_x or is the minimum x
115 * that is greater than target_x of all the
116 * lines straddling target_x.
117 * next->char_idx Set to -1 if no straddles target_y.
118 * Otherwise, set to the character that
119 * resides at target_x if target_x is in
120 * the middle of the line. Set to zero if
121 * target_x is before the line, and set to
122 * the line count if target_x is after the
125 *****************************************************************************/
127 SearchForClosestLine (
128 _DtCanvasStruct *canvas,
131 _DtCvSelectData *next)
139 _DtCvDspLine *lines = canvas->txt_lst;
141 *next = defaultSelect;
142 for (i = 0; i < canvas->txt_cnt; i++)
145 * get the maximum y of the line
146 * if it straddles the target y, process it.
148 lineY = lines[i].baseline + lines[i].descent;
149 if (_DtCvStraddlesPt(target_y,lines[i].baseline-lines[i].ascent,lineY))
152 * Is this the minimum y of all the maximum y values of the
153 * line straddling the target y?
155 if (next->y == -1 || next->y > lineY)
159 * Get the maximum X position of the line.
160 * If this is the maximum X of all the lines straddling
161 * the target y, remember it.
163 endX = canvas->txt_lst[i].max_x;
164 if (maxX < endX && endX < target_x)
171 * Does this line straddle the x?
173 begX = StartXOfLine(canvas, lines[i]);
174 if (_DtCvStraddlesPt(target_x, begX, endX))
177 next->char_idx = _DtCvGetCharIdx(canvas,lines[i],target_x);
183 * remember what the target x was for this line. If the target x is
184 * less than the start of the line, then the selection process will
185 * highlight the space before the line. If its in the middle, it
186 * will just highlight starting at the character. If it's after the
187 * end, the rest will be cut off at the end of the line.
192 * If we found a line straddling the target y, but it does not
193 * straddle the target_x, check max x for the correct info.
195 if (next->line_idx == -1 && maxX > -1)
197 next->line_idx = maxI;
198 next->char_idx = lines[maxI].length;
202 * didn't find a line straddling the target_y, set y.
208 /*****************************************************************************
209 * Function: MarkLinesOutsideBoundary
211 *****************************************************************************/
213 MarkLinesOutsideBoundary (
214 _DtCanvasStruct *canvas,
223 _DtCvDspLine *lines = canvas->txt_lst;
225 for (i = 0; i < canvas->txt_cnt; i++)
227 maxY = lines[i].baseline + lines[i].descent;
228 minY = lines[i].baseline - lines[i].ascent;
231 * is this line outside the boundary?
232 * If so, mark it so it's not processed.
234 if (maxY < top_y || minY > bot_y )
235 _DtCvSetProcessed(lines[i]);
240 * does it straddle the top?
242 if (_DtCvStraddlesPt(top_y, minY, maxY))
245 * Does it begin before the selection?
246 * If so, mark it so it's not processed.
248 if (canvas->txt_lst[i].max_x <= top_x)
249 _DtCvSetProcessed(lines[i]);
253 * does it straddle the bottom?
255 if (_DtCvStraddlesPt(bot_y, minY, maxY))
258 * Does it start after the selection?
259 * If so, mark it so it's not processed.
261 if (StartXOfLine(canvas, lines[i]) >= bot_x)
262 _DtCvSetProcessed(lines[i]);
268 /*****************************************************************************
269 * Function: AdjustSelection
271 *****************************************************************************/
274 _DtCanvasStruct *canvas,
275 _DtCvSelectData next)
277 _DtCvSelectData start = canvas->select_start;
278 _DtCvSelectData end = canvas->select_end;
280 if (!(Equal(next, end)))
282 if (next.line_idx != -1 && next.line_idx == canvas->select_end.line_idx
284 next.char_idx != -1 && next.char_idx == canvas->select_end.char_idx)
287 if (GreaterThan(next, end))
289 if (LessThanEq(start, end))
290 _DtCvDrawAreaWithFlags (canvas, end, next,
291 0, _DtCvSELECTED_FLAG,
292 _DtCvBAD_TYPE, NULL);
294 else if (GreaterThanEq(start, next))
295 _DtCvDrawAreaWithFlags (canvas, end, next,
296 _DtCvSELECTED_FLAG, 0,
297 _DtCvBAD_TYPE, NULL);
299 else /* end < start < next */
301 _DtCvDrawAreaWithFlags (canvas, end , start,
302 _DtCvSELECTED_FLAG, 0,
303 _DtCvBAD_TYPE, NULL);
304 _DtCvDrawAreaWithFlags (canvas, start, next ,
305 0, _DtCvSELECTED_FLAG,
306 _DtCvBAD_TYPE, NULL);
309 else /* if (next < end) */
311 if (LessThanEq(start, next))
312 _DtCvDrawAreaWithFlags (canvas, next, end,
313 _DtCvSELECTED_FLAG, 0,
314 _DtCvBAD_TYPE, NULL);
316 else if (GreaterThanEq(start, end))
317 _DtCvDrawAreaWithFlags (canvas, next, end,
318 0, _DtCvSELECTED_FLAG,
319 _DtCvBAD_TYPE, NULL);
321 else /* next < start < end */
323 _DtCvDrawAreaWithFlags (canvas, start, end ,
324 _DtCvSELECTED_FLAG, 0,
325 _DtCvBAD_TYPE, NULL);
326 _DtCvDrawAreaWithFlags (canvas, next , start,
327 0, _DtCvSELECTED_FLAG,
328 _DtCvBAD_TYPE, NULL);
333 canvas->select_end = next;
336 /*****************************************************************************
337 * Function: SkipOtherLines
339 *****************************************************************************/
348 while (idx < max_cnt && _DtCvIsNotProcessed(lines[idx]) &&
349 lines[idx].baseline - lines[idx].ascent > target_y)
355 /*****************************************************************************
356 * Function: CheckAndSwitchPoints
358 *****************************************************************************/
360 CheckAndSwitchPoints(
361 _DtCvSelectData *pt1,
362 _DtCvSelectData *pt2)
364 _DtCvSelectData temp;
366 if (pt1->y > pt2->y || (pt1->y == pt2->y && pt1->x > pt2->x))
374 /*****************************************************************************
375 * Function: AddSegmentToData
377 *****************************************************************************/
380 _DtCanvasStruct *canvas,
388 _DtCvPointer *ret_data)
390 _DtCvDspLine line = canvas->txt_lst[line_idx];
391 int result = _DtCvSTATUS_OK;
392 int count = line.length;
393 int start = line.byte_index;
398 _DtCvUnit xPos = line.text_x;
400 _DtCvSegmentI *pSeg = line.seg_ptr;
402 _DtCvValue done = False;
403 _DtCvValue lastLinkVisible = FALSE;
404 _DtCvStringInfo strInfo;
406 xPos = _DtCvGetStartXOfLine(&line, &pSeg);
408 while (done == False && char_idx)
411 * advance past the link and traversal info
413 xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos,
414 &lnkInd, &lastLinkVisible);
417 * advance the pointer by the width
419 _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
420 &cnt, &segWidth, NULL);
424 pSeg = pSeg->next_disp;
431 _DtCvGetWidthOfSegment(canvas, pSeg, start, char_idx,
432 &cnt, &segWidth, NULL);
443 while (_DtCvSTATUS_OK == result && pSeg != NULL && copy_cnt > 0)
446 * advance past the link and traversal info
448 xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos,
449 &lnkInd, &lastLinkVisible);
451 switch (_DtCvPrimaryTypeOfSeg(pSeg))
455 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
456 _DtCvIsSegWideChar(pSeg), start);
457 len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
462 segWidth = _DtCvGetStringWidth(canvas, pSeg, pChar, len);
466 strInfo.string = pChar;
467 strInfo.byte_len = len;
468 strInfo.wc = _DtCvIsSegWideChar(pSeg);
469 strInfo.font_ptr = _DtCvFontOfStringSeg(pSeg);
471 if (canvas->virt_functions.build_selection != NULL)
472 result = (*(canvas->virt_functions.build_selection))(
480 (_DtCvPointer) &strInfo);
482 if (_DtCvSTATUS_OK == result)
484 if (line.baseline + line.descent > *ret_y)
485 *ret_y = line.baseline + line.descent;
486 start_x = xPos + segWidth;
488 else if (_DtCvSTATUS_NONE == result)
489 result = _DtCvSTATUS_OK;
500 if (canvas->virt_functions.build_selection != NULL)
501 result = (*(canvas->virt_functions.build_selection))(
507 _DtCvWidthOfRegionSeg(pSeg),
509 _DtCvInfoOfRegionSeg(pSeg));
511 if (_DtCvSTATUS_OK == result)
513 if (line.baseline + line.descent > *ret_y)
514 *ret_y = line.baseline + line.descent;
515 start_x = xPos + segWidth;
517 else if (_DtCvSTATUS_NONE == result)
518 result = _DtCvSTATUS_OK;
521 xPos += _DtCvWidthOfRegionSeg(pSeg);
524 pSeg = pSeg->next_disp;
527 if (result != _DtCvSTATUS_OK)
533 /*****************************************************************************
534 * Function: BuildLine
536 *****************************************************************************/
539 _DtCanvasStruct *canvas,
549 _DtCvPointer *ret_data)
553 _DtCvDspLine *lines = canvas->txt_lst;
554 _DtCvStringInfo strInfo = { NULL, 0, 1, NULL };
556 topY = lines[line_idx].baseline - lines[line_idx].ascent;
557 if (topY > prev_y && canvas->virt_functions.build_selection != NULL)
560 _DtCvUnit lineSize = canvas->metrics.line_height / 2;
564 newLines = (topY - prev_y) / lineSize;
568 if ((*(canvas->virt_functions.build_selection))(
569 canvas->client_data, _DtCvSTRING_TYPE,
570 mask, ret_data, 0, 0, _DtCvEND_OF_LINE,
571 (_DtCvPointer) &strInfo) != _DtCvSTATUS_OK)
577 *ret_x = AddSegmentToData (canvas, mask, target_x, line_idx, char_idx,
578 copy_cnt, end_flag, ret_y, ret_data);
579 _DtCvSetProcessed(lines[line_idx]);
586 /*****************************************************************************
589 *****************************************************************************/
599 _DtCvUnit curMin = -1;
602 for (i = 0; i < txt_cnt; i++)
604 if (_DtCvIsNotProcessed(lines[i]))
606 if (lines[i].baseline - lines[i].ascent < target_y &&
607 target_y <= lines[i].baseline + lines[i].descent)
610 curX = lines[i].text_x;
612 if (curMin == -1 || curMin > curX)
623 /*****************************************************************************
624 * Function: FindNextMinY
626 *****************************************************************************/
636 _DtCvValue found = False;
640 if (_DtCvIsNotProcessed(lines[i]))
642 maxY = lines[i].baseline + lines[i].descent;
643 if (target_y == -1 || maxY < target_y)
648 SkipOtherLines (lines, max_cnt, i+1, target_y, &i);
658 /*****************************************************************************
659 * Function: GetSelectedText
661 *****************************************************************************/
664 _DtCanvasStruct *canvas,
665 _DtCvSelectData next,
668 _DtCvPointer *ret_data)
678 int txtCnt = canvas->txt_cnt;
680 _DtCvValue processing = True;
681 _DtCvDspLine *lines = canvas->txt_lst;
683 for (i = 0; i < txtCnt; i++)
684 _DtCvClearProcessed(lines[i]);
686 MarkLinesOutsideBoundary(canvas, next.y, next.x, end.y, end.x);
689 if (next.line_idx == -1)
692 * find the first selected line
694 if (FindNextMinY(lines, txtCnt, -1, &next.y) == False)
698 lineCnt = FindMinX(lines, txtCnt, next.y, &next.line_idx);
702 lineCnt = FindMinX(lines, txtCnt, next.y, &junk);
704 while (processing == True && result == 0)
707 * process the next line of text.
712 cpyCnt = lines[next.line_idx].length - next.char_idx;
713 if (next.line_idx == end.line_idx)
714 cpyCnt = cpyCnt - lines[next.line_idx].length + end.char_idx;
715 else if (lineCnt == 1)
716 endFlag = _DtCvEND_OF_LINE;
718 result = BuildLine(canvas, mask, maxY, next.x,
719 next.line_idx, next.char_idx,
721 &next.x, &botY, ret_data);
727 lineCnt = FindMinX(lines, txtCnt, next.y, &next.line_idx);
729 } while (result == 0 && lineCnt > 0);
734 processing = FindNextMinY(lines, txtCnt, -1, &next.y);
735 if (processing == True)
736 lineCnt = FindMinX(lines, txtCnt, next.y, &next.line_idx);
742 } /* End GetSelectedText */
744 /*****************************************************************************
745 * Function: GetSegsInArea()
747 * Purpose: Retrieve the segments making up the selection.
749 *****************************************************************************/
752 _DtCanvasStruct *canvas,
753 _DtCvSelectData *beg,
754 _DtCvSelectData *end,
755 _DtCvSegPts ***ret_segs,
765 _DtCvValue processing = True;
769 _DtCvSelectData next;
772 _DtCvDspLine *lines = canvas->txt_lst;
777 return _DtCvSTATUS_NONE;
780 * make sure the selection points are in the correct order.
782 CheckAndSwitchPoints(beg, end);
785 * clear the processed bit
787 for (cnt = 0; cnt < canvas->txt_cnt; cnt++)
788 _DtCvClearProcessed(lines[cnt]);
791 * initialize the working structure
792 * mark all the lines outside the selection regiion as invalid
795 MarkLinesOutsideBoundary(canvas, next.y, next.x, end->y, end->x);
798 * start the minimum and maximum Y at this location.
804 * is there a line at this location?
806 if (next.line_idx == -1)
809 * find the first selected line within the region.
811 if (FindNextMinY(lines, canvas->txt_cnt, -1, &next.y) == False)
812 processing = False; /* empty of any text */
816 * now find the first line that is on this 'line' and
817 * the number of lines.
820 lineCnt = FindMinX(lines, canvas->txt_cnt, next.y, &next.line_idx);
824 else /* find the number of lines on this 'line' */
825 lineCnt = FindMinX(lines, canvas->txt_cnt, next.y, &cnt);
828 * loop will there are segments to process
830 while (processing == True && result == 0)
833 * process the next line of text.
835 while (result == 0 && lineCnt > 0)
838 * for each segment in this line (that is selected)
839 * create a segment point for it.
841 length = lines[next.line_idx].length;
842 start = lines[next.line_idx].byte_index;
845 * if this is the last line, shorten the length
846 * by the ending index.
848 if (next.line_idx == end->line_idx)
849 length = end->char_idx;
852 * move through the line's segments until we
853 * hit the segment starting the selection
855 pSeg = lines[next.line_idx].seg_ptr;
856 count = next.char_idx;
857 while (NULL != pSeg && 0 < count)
860 * get the byte count of this segment
862 _DtCvGetWidthOfSegment(canvas, pSeg, start, length,
866 * is the byte count of this segment larger than
867 * the starting index of the selection? If not,
868 * the selection is after this segment.
874 pSeg = pSeg->next_disp;
879 start = start + count;
884 while (0 == result && NULL != pSeg && 0 < length)
887 * start with error condition. If the malloc works
888 * the error result gets reset to valid.
891 newPt = (_DtCvSegPts *) malloc (sizeof(_DtCvSegPts));
895 * indicate everything is okay.
900 * get the width of this segment
902 _DtCvGetWidthOfSegment(canvas, pSeg, start, length,
906 * now set the segment point information and add it to the
907 * array of segment points.
909 newPt->offset = start;
911 newPt->segment = pSeg;
913 *ret_segs = (_DtCvSegPts **) _DtCvAddPtrToArray(
916 if (NULL == *ret_segs)
919 pSeg = pSeg->next_disp;
926 * does this line extend below the selection y?
927 * if so, report it as the maximum y.
929 botY = lines[next.line_idx].baseline + lines[next.line_idx].descent;
934 * indicate this line has been processed.
936 _DtCvSetProcessed(lines[next.line_idx]);
942 lineCnt = FindMinX(lines, canvas->txt_cnt, next.y,
949 processing = FindNextMinY(lines,canvas->txt_cnt, -1, &next.y);
950 if (processing == True)
951 lineCnt = FindMinX(lines,canvas->txt_cnt,next.y,&next.line_idx);
956 * if no errors, add a null to the array
960 *ret_segs = (_DtCvSegPts **) _DtCvAddPtrToArray((void **) *ret_segs,
962 if (NULL == *ret_segs)
967 * if errors, free the segment points and return a bad status.
971 if (NULL != *ret_segs)
973 for (lineCnt = 0; NULL != (*ret_segs)[lineCnt]; lineCnt++)
974 free((*ret_segs)[lineCnt]);
977 return _DtCvSTATUS_BAD;
986 return _DtCvSTATUS_OK;
989 /******************************************************************************
990 * Semi-Public Functions
991 ******************************************************************************/
992 /*****************************************************************************
993 * Function: _DtCvDrawAreaWithFlags
995 *****************************************************************************/
997 _DtCvDrawAreaWithFlags (
998 _DtCanvasStruct *canvas,
999 _DtCvSelectData start,
1000 _DtCvSelectData end,
1001 _DtCvFlags old_flags,
1002 _DtCvFlags new_flags,
1003 _DtCvElemType trav_type,
1004 _DtCvPointer trav_data)
1014 _DtCvUnit superWidth;
1020 _DtCvSegmentI *pSeg;
1021 _DtCvValue lstLinkVis;
1022 _DtCvValue lstWasSuper;
1023 _DtCvValue lstWasSub;
1025 _DtCvFlags flagMask = old_flags | new_flags;
1026 _DtCvFlags endFlag = flagMask & _DtCvTRAVERSAL_END;
1028 _DtCvDspLine *lines = canvas->txt_lst;
1031 * now use the flagMask to determine what else to look for.
1032 * I.e. if flagMask has _DtCvMARK_FLAG set, then it becomes
1033 * set to _DtCvSELECTED_FLAG and visa versa.
1035 flagMask ^= (_DtCvSELECTED_FLAG | _DtCvMARK_FLAG);
1038 * strip the end flag from the other flags
1040 new_flags &= ~(_DtCvTRAVERSAL_END);
1041 old_flags &= ~(_DtCvTRAVERSAL_END);
1043 if (Equal(start, end))
1046 for (i = 0; i < canvas->txt_cnt; i++)
1048 topY = lines[i].baseline - lines[i].ascent;
1049 botY = lines[i].baseline + lines[i].descent;
1051 if (InRegion(topY, botY, start.y, end.y))
1054 * get the start of the text.
1057 lstWasSuper = False;
1060 dstX = _DtCvGetStartXOfLine(&(lines[i]), &pSeg);
1061 startChar = lines[i].byte_index;
1062 count = lines[i].length;
1064 while (pSeg != NULL && _DtCvIsSegNoop(pSeg))
1067 pSeg = pSeg->next_disp;
1071 * advance the starting point
1073 dstX = _DtCvAdvanceXOfLine(canvas, pSeg, dstX,
1074 &lnkInd, &lstLinkVis);
1076 * take into account super/sub scripting
1078 dstX = _DtCvAdjustForSuperSub(canvas, pSeg, dstX, &scriptX,
1079 &superWidth, &superY, &subWidth, &subY,
1080 &lstWasSuper, &lstWasSub);
1083 * set this flag so that the first pass of 'while (cnt > 0)'
1084 * doesn't do it again.
1088 if (_DtCvStraddlesPt(start.y, topY, botY))
1092 * I.E. is this line before the start or after the end?
1094 if (canvas->txt_lst[i].max_x < start.x ||
1095 end.y == start.y && end.x <= dstX )
1099 * does this line start the mark/selection?
1101 if (i == start.line_idx && start.x >= dstX)
1103 int cnt = start.char_idx;
1107 if (trimmed == False)
1110 * advance the starting point
1112 dstX = _DtCvAdvanceXOfLine(canvas, pSeg, dstX,
1113 &lnkInd, &lstLinkVis);
1115 * take into account super/sub scripting
1117 dstX = _DtCvAdjustForSuperSub(canvas,
1118 pSeg, dstX, &scriptX,
1119 &superWidth, &superY, &subWidth, &subY,
1120 &lstWasSuper, &lstWasSub);
1124 * take into account the length of the segment
1126 _DtCvGetWidthOfSegment(canvas, pSeg,
1128 &len, &segWidth, &trimmed);
1132 if (trimmed == False)
1135 pSeg = pSeg->next_disp;
1144 count -= start.char_idx;
1148 * otherwise this line is after the line that starts
1149 * the mark/selection. Stick with its start x.
1154 * does this straddle the end point?
1156 if (_DtCvStraddlesPt(end.y, topY, botY))
1159 * does this start after the end of the mark/selection?
1166 * Does this segment end after the end of the mark/selection?
1167 * If so, trim how much gets highlighted.
1169 if (canvas->txt_lst[i].max_x > end.x)
1170 count -= (lines[i].length - end.char_idx);
1174 * while there is something to draw (un)mark/selected.
1176 old_flags = old_flags | _DtCvMARK_BEGIN;
1177 new_flags = new_flags | _DtCvMARK_BEGIN;
1181 * the original count to render
1186 * check for other marks and selection.
1188 _DtCvCheckLineMarks(canvas, i, startChar - lines[i].byte_index,
1189 count, dstX, flagMask,
1190 &len, &old_flags, &new_flags);
1193 * if this is the last segment(s) of the (un)mark/selection
1194 * set the end flags.
1198 new_flags |= (endFlag | _DtCvLINK_END | _DtCvMARK_END);
1199 old_flags |= (endFlag | _DtCvLINK_END | _DtCvMARK_END);
1203 * draw the segments that are marked/unmarked.
1205 dstX = _DtCvDrawSegments(canvas, lines[i],
1206 pSeg, startChar , len, &lnkInd,
1207 dstX, dstX, &scriptX,
1208 &superWidth, &superY, &subWidth, &subY,
1209 &lstWasSub, &lstWasSuper,
1210 &lstLinkVis, old_flags, new_flags,
1211 trav_type, trav_data);
1213 * modify the count by the length processed
1218 * did this do the entire length? If not, set the
1219 * indexes ahead and do again.
1222 _DtCvSkipLineChars(canvas, pSeg, startChar , count + len,
1223 len, &startChar , &pSeg);
1226 * strip the any begin flags.
1228 _DtCvRemoveBeginFlags(old_flags);
1229 _DtCvRemoveBeginFlags(new_flags);
1235 /*****************************************************************************
1236 * Function: _DtCanvasGetSelectionPoints()
1238 * Purpose: Retrieve the segments making up the selection.
1240 *****************************************************************************/
1243 _DtCanvasStruct *canvas,
1244 _DtCvPointInfo ***ret_info)
1250 for (i = 0; i < canvas->mark_cnt; i++)
1252 _DtCvPointInfo *nxtInfo;
1255 * allocate mark information structure
1257 nxtInfo = (_DtCvPointInfo *) malloc (sizeof(_DtCvPointInfo));
1258 if (NULL == nxtInfo)
1259 return _DtCvSTATUS_BAD;
1261 nxtInfo->client_data = canvas->marks[i].client_data;
1263 if (_DtCvSTATUS_BAD == GetSegsInArea(canvas, &(canvas->marks[i].beg),
1264 &(canvas->marks[i].end),
1267 return _DtCvSTATUS_BAD;
1269 *ret_info = (_DtCvPointInfo **) _DtCvAddPtrToArray((void **) *ret_info,
1271 if (NULL == *ret_info)
1272 return _DtCvSTATUS_BAD;
1275 return _DtCvSTATUS_OK;
1278 /******************************************************************************
1280 ******************************************************************************/
1281 /*****************************************************************************
1282 * Function: _DtCanvasGetSelection()
1284 * Purpose: Indicate the end point for a selection.
1286 *****************************************************************************/
1288 _DtCanvasGetSelection (
1289 _DtCvHandle canvas_handle,
1291 _DtCvPointer *ret_select)
1293 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1296 return(GetSelectedText(canvas, canvas->select_start, canvas->select_end,
1300 /*****************************************************************************
1301 * Function: _DtCanvasProcessSelection()
1303 * Purpose: Indicate an new point for a selection.
1305 *****************************************************************************/
1307 _DtCanvasProcessSelection (
1308 _DtCvHandle canvas_handle,
1311 _DtCvSelectMode mode)
1314 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1315 _DtCvSelectData temp;
1319 case _DtCvSELECTION_CLEAR:
1320 CheckAndSwitchPoints(&(canvas->select_start),
1321 &(canvas->select_end));
1323 case _DtCvSELECTION_START:
1324 _DtCvDrawAreaWithFlags(canvas, canvas->select_start,
1326 _DtCvSELECTED_FLAG, 0,
1327 _DtCvBAD_TYPE, NULL);
1329 canvas->select_start = defaultSelect;
1330 if (mode == _DtCvSELECTION_START)
1331 SearchForClosestLine(canvas, x, y, &(canvas->select_start));
1333 canvas->select_end = canvas->select_start;
1336 case _DtCvSELECTION_END:
1337 case _DtCvSELECTION_UPDATE:
1338 SearchForClosestLine(canvas, x, y, &temp);
1340 AdjustSelection (canvas, temp);
1341 if (mode == _DtCvSELECTION_END)
1342 CheckAndSwitchPoints(&(canvas->select_start),
1343 &(canvas->select_end));
1348 /*****************************************************************************
1349 * Function: _DtCanvasGetSelectionPoints()
1351 * Purpose: Retrieve the segments making up the selection.
1353 *****************************************************************************/
1355 _DtCanvasGetSelectionPoints (
1356 _DtCvHandle canvas_handle,
1357 _DtCvSegPts ***ret_segs,
1361 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1363 return (GetSegsInArea(canvas, &(canvas->select_start),
1364 &(canvas->select_end), ret_segs, ret_y1, ret_y2));
1367 /*****************************************************************************
1368 * Function: _DtCanvasActivatePts()
1370 * Purpose: Activate the points given.
1372 *****************************************************************************/
1374 _DtCanvasActivatePts (
1375 _DtCvHandle canvas_handle,
1377 _DtCvPointInfo *info,
1382 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1383 _DtCvSelectData startSel = defaultSelect;
1384 _DtCvSelectData endSel = defaultSelect;
1386 _DtCvSegmentI *firstSeg;
1388 #define REQUIRE_SEGS \
1389 (_DtCvACTIVATE_MARK | _DtCvACTIVATE_SELECTION)
1391 * check to see if there is anything to do
1394 return _DtCvSTATUS_NONE;
1396 if ((mask & _DtCvACTIVATE_MARK) && (mask & _DtCvDEACTIVATE))
1397 return _DtCvSTATUS_BAD;
1400 * Convert the segments into starting and ending positions.
1402 if (((mask & _DtCvDEACTIVATE) && NULL == info->client_data)
1403 || (mask & REQUIRE_SEGS))
1405 if (NULL == info || NULL == info->segs ||
1406 _DtCvSTATUS_BAD == _DtCvCvtSegsToPts(canvas, info->segs,
1408 ret_y1, ret_y2, &firstSeg))
1409 return _DtCvSTATUS_BAD;
1413 * Activate as a selection
1415 if (mask & _DtCvACTIVATE_SELECTION)
1417 _DtCanvasProcessSelection (canvas_handle, 0, 0, _DtCvSELECTION_CLEAR);
1419 canvas->select_start = startSel;
1420 canvas->select_end = endSel;
1422 _DtCvDrawAreaWithFlags (canvas, startSel, endSel,
1423 0, _DtCvSELECTED_FLAG,
1424 _DtCvBAD_TYPE, NULL);
1428 * Activate as a mark
1430 if (mask & _DtCvACTIVATE_MARK)
1438 markIdx = _DtCvAddToMarkList(canvas, info->client_data,
1439 _DtCvIsMarkMaskOn(mask), &startSel, &endSel);
1441 return _DtCvSTATUS_BAD;
1444 * now put the mark in the traversal list and merge it into the
1447 travIdx = _DtCvGetNextTravEntry(canvas);
1449 || 0 != _DtCvSetTravEntryInfo(canvas, travIdx,
1450 _DtCvTraversalMark, firstSeg,
1452 || 0 != _DtCvCalcMarkPos(canvas, markIdx,
1453 &x, &y, &width, &height)
1454 || 0 != _DtCvSetTravEntryPos(canvas, travIdx,
1455 x, y, width, height))
1456 return _DtCvSTATUS_BAD;
1458 _DtCvSortTraversalList(canvas, _DtCvTRUE);
1461 * draw these segments marked.
1463 flag = _DtCvMARK_FLAG;
1464 if (_DtCvTRUE == canvas->marks[markIdx].on)
1465 flag |= _DtCvMARK_ON;
1467 _DtCvDrawAreaWithFlags (canvas, startSel, endSel,
1469 _DtCvBAD_TYPE, NULL);
1473 * Clear the mark flag.
1475 else if (mask & _DtCvDEACTIVATE)
1480 * is there anything to deacivate?
1482 if (NULL == canvas->marks || 0 == canvas->mark_cnt)
1483 return _DtCvSTATUS_BAD;
1486 * was client data specified? If so, then look for it and ignore
1490 if (NULL != info->client_data)
1492 while (markIdx < canvas->mark_cnt &&
1493 canvas->marks[markIdx].client_data != info->client_data)
1497 * initialize the selection points
1499 if (markIdx < canvas->mark_cnt)
1501 startSel = canvas->marks[markIdx].beg;
1502 endSel = canvas->marks[markIdx].end;
1506 * look for the marked set using the segments.
1510 while (markIdx < canvas->mark_cnt
1511 && startSel.line_idx != canvas->marks[markIdx].beg.line_idx
1512 && startSel.char_idx != canvas->marks[markIdx].beg.char_idx
1513 && endSel.line_idx != canvas->marks[markIdx].end.line_idx
1514 && endSel.line_idx != canvas->marks[markIdx].end.char_idx)
1518 if (markIdx >= canvas->mark_cnt)
1519 return _DtCvSTATUS_BAD;
1522 * draw these segments unmarked.
1524 flag = _DtCvMARK_FLAG;
1525 if (_DtCvTRUE == canvas->marks[markIdx].on)
1526 flag |= _DtCvMARK_ON;
1528 canvas->marks[markIdx].on = _DtCvFALSE;
1529 _DtCvDrawAreaWithFlags (canvas, startSel, endSel, flag, 0,
1530 _DtCvBAD_TYPE, NULL);
1533 * remove the mark from the traversal list
1535 * first find the traversal entry of the mark and adjust any
1536 * traversal mark index values to reflect that the mark
1537 * list is about to shrink by 1.
1539 for (travIdx = 0; _DtCvTraversalMark != canvas->trav_lst[travIdx].type
1540 || markIdx != canvas->trav_lst[travIdx].idx; travIdx++)
1543 * is this mark after the one being removed?
1544 * if so, decrease its index because it's about to move.
1546 if (_DtCvTraversalMark == canvas->trav_lst[travIdx].type &&
1547 markIdx < canvas->trav_lst[travIdx].idx)
1548 canvas->trav_lst[travIdx].idx--;
1552 * move the list of traversal entries to eliminate the mark entry.
1554 while (travIdx + 1 < canvas->trav_cnt)
1556 canvas->trav_lst[travIdx] = canvas->trav_lst[travIdx + 1];
1559 * is this a mark after the one being removed?
1560 * if so, decrease it's index because it's about to move.
1562 if (_DtCvTraversalMark == canvas->trav_lst[travIdx].type &&
1563 markIdx < canvas->trav_lst[travIdx].idx)
1564 canvas->trav_lst[travIdx].idx--;
1570 * update the traversal count and back up to the previous traversal
1571 * if the mark was at the end of the traversal list.
1574 if (canvas->cur_trav >= canvas->trav_cnt)
1578 * move the list of marks up
1580 while (markIdx + 1 < canvas->mark_cnt)
1582 canvas->marks[markIdx] = canvas->marks[markIdx + 1];
1588 else if ((_DtCvACTIVATE_MARK_ON | _DtCvACTIVATE_MARK_OFF) & mask)
1591 if (NULL != info && NULL != info->client_data)
1593 while (markIdx < canvas->mark_cnt &&
1594 canvas->marks[markIdx].client_data != info->client_data)
1598 * was a mark with this client data found?
1600 if (markIdx >= canvas->mark_cnt)
1601 return _DtCvSTATUS_BAD;
1606 * are there any traversals? Is the current one sitting on a mark?
1608 if (0 == canvas->trav_cnt || -1 == canvas->cur_trav ||
1609 _DtCvTraversalMark != canvas->trav_lst[canvas->cur_trav].type)
1610 return _DtCvSTATUS_BAD;
1613 * get the mark index
1615 markIdx = canvas->trav_lst[canvas->cur_trav].idx;
1619 * is this different than what it is set at now? If not, do nothing.
1621 if (_DtCvIsMarkMaskOn(mask) == canvas->marks[markIdx].on)
1622 return _DtCvSTATUS_NONE;
1625 * set to mask value.
1627 canvas->marks[markIdx].on = _DtCvIsMarkMaskOn(mask);
1630 * set the flags correctly.
1632 flag = _DtCvMARK_FLAG;
1633 if (_DtCvTRUE == canvas->marks[markIdx].on)
1634 flag |= _DtCvMARK_ON;
1635 if (_DtCvTRUE == canvas->trav_on &&
1636 markIdx == canvas->trav_lst[canvas->cur_trav].idx)
1637 flag |= _DtCvTRAVERSAL_FLAG;
1640 * draw the mark opposite what it was
1642 _DtCvDrawAreaWithFlags (canvas, canvas->marks[markIdx].beg,
1643 canvas->marks[markIdx].end,
1644 (flag ^ _DtCvMARK_ON), flag,
1645 _DtCvBAD_TYPE, NULL);
1648 return _DtCvSTATUS_OK;
1651 /*****************************************************************************
1652 * Function: _DtCanvasGetMarkPositions()
1654 * Purpose: Return the position in the canvas of the marks.
1656 *****************************************************************************/
1658 _DtCanvasGetMarkPositions (
1659 _DtCvHandle canvas_handle,
1660 _DtCvMarkPos ***ret_pos)
1663 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1664 _DtCvMarkPos *nextPos;
1665 _DtCvMarkData *markLst = canvas->marks;
1669 if (0 == canvas->mark_cnt)
1670 return _DtCvSTATUS_NONE;
1672 for (i = 0; i < canvas->mark_cnt; i++, markLst++)
1675 * malloc memory for the information
1677 nextPos = (_DtCvMarkPos *) malloc (sizeof(_DtCvMarkPos));
1678 if (NULL == nextPos)
1679 return _DtCvSTATUS_BAD;
1682 * client data and baselines
1684 nextPos->client_data = markLst->client_data;
1685 nextPos->baseline1 = canvas->txt_lst[markLst->beg.line_idx].baseline;
1686 nextPos->baseline2 = canvas->txt_lst[markLst->end.line_idx].baseline;
1691 nextPos->x1 = markLst->beg.x;
1692 nextPos->y1 = nextPos->baseline1 -
1693 canvas->txt_lst[markLst->beg.line_idx].ascent;
1696 * bottom right corner
1698 nextPos->x2 = markLst->end.x;
1699 nextPos->y2 = nextPos->baseline2 +
1700 canvas->txt_lst[markLst->end.line_idx].descent;
1702 *ret_pos = (_DtCvMarkPos **) _DtCvAddPtrToArray((void **) *ret_pos,
1704 if (NULL == *ret_pos)
1705 return _DtCvSTATUS_BAD;
1708 return _DtCvSTATUS_OK;