2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: Selection.c /main/22 1996/11/12 11:44:48 cde-hp $ */
24 /************************************<+>*************************************
25 ****************************************************************************
29 ** Project: Cde DtHelp
31 ** (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
33 ** (c) Copyright 1993, 1994 Hewlett-Packard Company
34 ** (c) Copyright 1993, 1994 International Business Machines Corp.
35 ** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
36 ** (c) Copyright 1993, 1994 Novell, Inc.
39 ****************************************************************************
40 ************************************<+>*************************************/
49 * Canvas Engine includes
52 #include "CanvasSegP.h"
58 #include "CvStringI.h"
59 #include "LayoutUtilI.h"
60 #include "SelectionI.h"
65 /******** Private Function Declarations ********/
66 static void AdjustSelection (
67 _DtCanvasStruct *canvas,
68 _DtCvSelectData next);
69 static int GetSelectedText(
70 _DtCanvasStruct *canvas,
71 _DtCvSelectData start,
74 _DtCvPointer *ret_data);
75 /******** End Private Function Declarations ********/
77 /******** Private Defines ********/
79 /******** End Private Defines ********/
81 /******** Macros ********/
82 #define Equal(a,b) (a.y == b.y && a.x == b.x)
83 #define LessThan(a,b) ((a.y < b.y) || (a.y == b.y && a.x < b.x))
84 #define GreaterThan(a,b) ((a.y > b.y) || (a.y == b.y && a.x > b.x))
85 #define LessThanEq(a,b) (Equal(a,b) || LessThan(a,b))
86 #define GreaterThanEq(a,b) (Equal(a,b) || GreaterThan(a,b))
88 #define InRegion(top,bot,min,max) ((min) <= (bot) && (top) <= (max))
90 /******** End Macros ********/
92 /******** Private Variable Declarations ********/
93 static const _DtCvSelectData defaultSelect = { -1, -1, -1, -1};
95 /******** End Private Variable Declarations ********/
97 /******************************************************************************
99 ******************************************************************************/
100 /******************************************************************************
101 * Function: StartXOfLine
103 * Purpose: Determine the start of a line, takes into consideration
104 * the traversal and link before values. The 'x' returned is
105 * exactly where the text/graphic is to be placed on the canvas.
106 *****************************************************************************/
109 _DtCanvasStruct *canvas,
112 _DtCvValue lastLinkVisible = FALSE;
117 xPos = _DtCvGetStartXOfLine(&line, &pSeg);
118 return (_DtCvAdvanceXOfLine( canvas, pSeg, xPos,
119 &lnkInd, &lastLinkVisible));
121 } /* End StartXOfLine */
123 /*****************************************************************************
124 * Function: SearchForClosestLine
126 * Purpose: Initializes the 'new' structure with information indicating
127 * what line is closest to the target_y.
128 * next->y Set to target_y if no line straddles it.
129 * Otherwise, it will be set to the minimum
130 * y of all lines straddling the target_y.
131 * next->x Set to target_x if no line straddles
132 * target_y or if target_x is before the
133 * first line straddling target_y.
134 * next->line_idx Set to -1 if no line straddles target_y.
135 * Otherwise, set to the first line that
136 * straddles target_x or is the minimum x
137 * that is greater than target_x of all the
138 * lines straddling target_x.
139 * next->char_idx Set to -1 if no straddles target_y.
140 * Otherwise, set to the character that
141 * resides at target_x if target_x is in
142 * the middle of the line. Set to zero if
143 * target_x is before the line, and set to
144 * the line count if target_x is after the
147 *****************************************************************************/
149 SearchForClosestLine (
150 _DtCanvasStruct *canvas,
153 _DtCvSelectData *next)
161 _DtCvDspLine *lines = canvas->txt_lst;
163 *next = defaultSelect;
164 for (i = 0; i < canvas->txt_cnt; i++)
167 * get the maximum y of the line
168 * if it straddles the target y, process it.
170 lineY = lines[i].baseline + lines[i].descent;
171 if (_DtCvStraddlesPt(target_y,lines[i].baseline-lines[i].ascent,lineY))
174 * Is this the minimum y of all the maximum y values of the
175 * line straddling the target y?
177 if (next->y == -1 || next->y > lineY)
181 * Get the maximum X position of the line.
182 * If this is the maximum X of all the lines straddling
183 * the target y, remember it.
185 endX = canvas->txt_lst[i].max_x;
186 if (maxX < endX && endX < target_x)
193 * Does this line straddle the x?
195 begX = StartXOfLine(canvas, lines[i]);
196 if (_DtCvStraddlesPt(target_x, begX, endX))
199 next->char_idx = _DtCvGetCharIdx(canvas,lines[i],target_x);
205 * remember what the target x was for this line. If the target x is
206 * less than the start of the line, then the selection process will
207 * highlight the space before the line. If its in the middle, it
208 * will just highlight starting at the character. If it's after the
209 * end, the rest will be cut off at the end of the line.
214 * If we found a line straddling the target y, but it does not
215 * straddle the target_x, check max x for the correct info.
217 if (next->line_idx == -1 && maxX > -1)
219 next->line_idx = maxI;
220 next->char_idx = lines[maxI].length;
224 * didn't find a line straddling the target_y, set y.
230 /*****************************************************************************
231 * Function: MarkLinesOutsideBoundary
233 *****************************************************************************/
235 MarkLinesOutsideBoundary (
236 _DtCanvasStruct *canvas,
245 _DtCvDspLine *lines = canvas->txt_lst;
247 for (i = 0; i < canvas->txt_cnt; i++)
249 maxY = lines[i].baseline + lines[i].descent;
250 minY = lines[i].baseline - lines[i].ascent;
253 * is this line outside the boundary?
254 * If so, mark it so it's not processed.
256 if (maxY < top_y || minY > bot_y )
257 _DtCvSetProcessed(lines[i]);
262 * does it straddle the top?
264 if (_DtCvStraddlesPt(top_y, minY, maxY))
267 * Does it begin before the selection?
268 * If so, mark it so it's not processed.
270 if (canvas->txt_lst[i].max_x <= top_x)
271 _DtCvSetProcessed(lines[i]);
275 * does it straddle the bottom?
277 if (_DtCvStraddlesPt(bot_y, minY, maxY))
280 * Does it start after the selection?
281 * If so, mark it so it's not processed.
283 if (StartXOfLine(canvas, lines[i]) >= bot_x)
284 _DtCvSetProcessed(lines[i]);
290 /*****************************************************************************
291 * Function: AdjustSelection
293 *****************************************************************************/
296 _DtCanvasStruct *canvas,
297 _DtCvSelectData next)
299 _DtCvSelectData start = canvas->select_start;
300 _DtCvSelectData end = canvas->select_end;
302 if (!(Equal(next, end)))
304 if (next.line_idx != -1 && next.line_idx == canvas->select_end.line_idx
306 next.char_idx != -1 && next.char_idx == canvas->select_end.char_idx)
309 if (GreaterThan(next, end))
311 if (LessThanEq(start, end))
312 _DtCvDrawAreaWithFlags (canvas, end, next,
313 0, _DtCvSELECTED_FLAG,
314 _DtCvBAD_TYPE, NULL);
316 else if (GreaterThanEq(start, next))
317 _DtCvDrawAreaWithFlags (canvas, end, next,
318 _DtCvSELECTED_FLAG, 0,
319 _DtCvBAD_TYPE, NULL);
321 else /* end < start < next */
323 _DtCvDrawAreaWithFlags (canvas, end , start,
324 _DtCvSELECTED_FLAG, 0,
325 _DtCvBAD_TYPE, NULL);
326 _DtCvDrawAreaWithFlags (canvas, start, next ,
327 0, _DtCvSELECTED_FLAG,
328 _DtCvBAD_TYPE, NULL);
331 else /* if (next < end) */
333 if (LessThanEq(start, next))
334 _DtCvDrawAreaWithFlags (canvas, next, end,
335 _DtCvSELECTED_FLAG, 0,
336 _DtCvBAD_TYPE, NULL);
338 else if (GreaterThanEq(start, end))
339 _DtCvDrawAreaWithFlags (canvas, next, end,
340 0, _DtCvSELECTED_FLAG,
341 _DtCvBAD_TYPE, NULL);
343 else /* next < start < end */
345 _DtCvDrawAreaWithFlags (canvas, start, end ,
346 _DtCvSELECTED_FLAG, 0,
347 _DtCvBAD_TYPE, NULL);
348 _DtCvDrawAreaWithFlags (canvas, next , start,
349 0, _DtCvSELECTED_FLAG,
350 _DtCvBAD_TYPE, NULL);
355 canvas->select_end = next;
358 /*****************************************************************************
359 * Function: SkipOtherLines
361 *****************************************************************************/
370 while (idx < max_cnt && _DtCvIsNotProcessed(lines[idx]) &&
371 lines[idx].baseline - lines[idx].ascent > target_y)
377 /*****************************************************************************
378 * Function: CheckAndSwitchPoints
380 *****************************************************************************/
382 CheckAndSwitchPoints(
383 _DtCvSelectData *pt1,
384 _DtCvSelectData *pt2)
386 _DtCvSelectData temp;
388 if (pt1->y > pt2->y || (pt1->y == pt2->y && pt1->x > pt2->x))
396 /*****************************************************************************
397 * Function: AddSegmentToData
399 *****************************************************************************/
402 _DtCanvasStruct *canvas,
410 _DtCvPointer *ret_data)
412 _DtCvDspLine line = canvas->txt_lst[line_idx];
413 int result = _DtCvSTATUS_OK;
414 int count = line.length;
415 int start = line.byte_index;
420 _DtCvUnit xPos = line.text_x;
422 _DtCvSegmentI *pSeg = line.seg_ptr;
424 _DtCvValue done = False;
425 _DtCvValue lastLinkVisible = FALSE;
426 _DtCvStringInfo strInfo;
428 xPos = _DtCvGetStartXOfLine(&line, &pSeg);
430 while (done == False && char_idx)
433 * advance past the link and traversal info
435 xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos,
436 &lnkInd, &lastLinkVisible);
439 * advance the pointer by the width
441 _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
442 &cnt, &segWidth, NULL);
446 pSeg = pSeg->next_disp;
453 _DtCvGetWidthOfSegment(canvas, pSeg, start, char_idx,
454 &cnt, &segWidth, NULL);
465 while (_DtCvSTATUS_OK == result && pSeg != NULL && copy_cnt > 0)
468 * advance past the link and traversal info
470 xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos,
471 &lnkInd, &lastLinkVisible);
473 switch (_DtCvPrimaryTypeOfSeg(pSeg))
477 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
478 _DtCvIsSegWideChar(pSeg), start);
479 len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
484 segWidth = _DtCvGetStringWidth(canvas, pSeg, pChar, len);
488 strInfo.string = pChar;
489 strInfo.byte_len = len;
490 strInfo.wc = _DtCvIsSegWideChar(pSeg);
491 strInfo.font_ptr = _DtCvFontOfStringSeg(pSeg);
493 if (canvas->virt_functions.build_selection != NULL)
494 result = (*(canvas->virt_functions.build_selection))(
502 (_DtCvPointer) &strInfo);
504 if (_DtCvSTATUS_OK == result)
506 if (line.baseline + line.descent > *ret_y)
507 *ret_y = line.baseline + line.descent;
508 start_x = xPos + segWidth;
510 else if (_DtCvSTATUS_NONE == result)
511 result = _DtCvSTATUS_OK;
522 if (canvas->virt_functions.build_selection != NULL)
523 result = (*(canvas->virt_functions.build_selection))(
529 _DtCvWidthOfRegionSeg(pSeg),
531 _DtCvInfoOfRegionSeg(pSeg));
533 if (_DtCvSTATUS_OK == result)
535 if (line.baseline + line.descent > *ret_y)
536 *ret_y = line.baseline + line.descent;
537 start_x = xPos + segWidth;
539 else if (_DtCvSTATUS_NONE == result)
540 result = _DtCvSTATUS_OK;
543 xPos += _DtCvWidthOfRegionSeg(pSeg);
546 pSeg = pSeg->next_disp;
549 if (result != _DtCvSTATUS_OK)
555 /*****************************************************************************
556 * Function: BuildLine
558 *****************************************************************************/
561 _DtCanvasStruct *canvas,
571 _DtCvPointer *ret_data)
575 _DtCvDspLine *lines = canvas->txt_lst;
576 _DtCvStringInfo strInfo = { NULL, 0, 1, NULL };
578 topY = lines[line_idx].baseline - lines[line_idx].ascent;
579 if (topY > prev_y && canvas->virt_functions.build_selection != NULL)
582 _DtCvUnit lineSize = canvas->metrics.line_height / 2;
586 newLines = (topY - prev_y) / lineSize;
590 if ((*(canvas->virt_functions.build_selection))(
591 canvas->client_data, _DtCvSTRING_TYPE,
592 mask, ret_data, 0, 0, _DtCvEND_OF_LINE,
593 (_DtCvPointer) &strInfo) != _DtCvSTATUS_OK)
599 *ret_x = AddSegmentToData (canvas, mask, target_x, line_idx, char_idx,
600 copy_cnt, end_flag, ret_y, ret_data);
601 _DtCvSetProcessed(lines[line_idx]);
608 /*****************************************************************************
611 *****************************************************************************/
621 _DtCvUnit curMin = -1;
624 for (i = 0; i < txt_cnt; i++)
626 if (_DtCvIsNotProcessed(lines[i]))
628 if (lines[i].baseline - lines[i].ascent < target_y &&
629 target_y <= lines[i].baseline + lines[i].descent)
632 curX = lines[i].text_x;
634 if (curMin == -1 || curMin > curX)
645 /*****************************************************************************
646 * Function: FindNextMinY
648 *****************************************************************************/
658 _DtCvValue found = False;
662 if (_DtCvIsNotProcessed(lines[i]))
664 maxY = lines[i].baseline + lines[i].descent;
665 if (target_y == -1 || maxY < target_y)
670 SkipOtherLines (lines, max_cnt, i+1, target_y, &i);
680 /*****************************************************************************
681 * Function: GetSelectedText
683 *****************************************************************************/
686 _DtCanvasStruct *canvas,
687 _DtCvSelectData next,
690 _DtCvPointer *ret_data)
700 int txtCnt = canvas->txt_cnt;
702 _DtCvValue processing = True;
703 _DtCvDspLine *lines = canvas->txt_lst;
705 for (i = 0; i < txtCnt; i++)
706 _DtCvClearProcessed(lines[i]);
708 MarkLinesOutsideBoundary(canvas, next.y, next.x, end.y, end.x);
711 if (next.line_idx == -1)
714 * find the first selected line
716 if (FindNextMinY(lines, txtCnt, -1, &next.y) == False)
720 lineCnt = FindMinX(lines, txtCnt, next.y, &next.line_idx);
724 lineCnt = FindMinX(lines, txtCnt, next.y, &junk);
726 while (processing == True && result == 0)
729 * process the next line of text.
734 cpyCnt = lines[next.line_idx].length - next.char_idx;
735 if (next.line_idx == end.line_idx)
736 cpyCnt = cpyCnt - lines[next.line_idx].length + end.char_idx;
737 else if (lineCnt == 1)
738 endFlag = _DtCvEND_OF_LINE;
740 result = BuildLine(canvas, mask, maxY, next.x,
741 next.line_idx, next.char_idx,
743 &next.x, &botY, ret_data);
749 lineCnt = FindMinX(lines, txtCnt, next.y, &next.line_idx);
751 } while (result == 0 && lineCnt > 0);
756 processing = FindNextMinY(lines, txtCnt, -1, &next.y);
757 if (processing == True)
758 lineCnt = FindMinX(lines, txtCnt, next.y, &next.line_idx);
764 } /* End GetSelectedText */
766 /*****************************************************************************
767 * Function: GetSegsInArea()
769 * Purpose: Retrieve the segments making up the selection.
771 *****************************************************************************/
774 _DtCanvasStruct *canvas,
775 _DtCvSelectData *beg,
776 _DtCvSelectData *end,
777 _DtCvSegPts ***ret_segs,
787 _DtCvValue processing = True;
791 _DtCvSelectData next;
794 _DtCvDspLine *lines = canvas->txt_lst;
799 return _DtCvSTATUS_NONE;
802 * make sure the selection points are in the correct order.
804 CheckAndSwitchPoints(beg, end);
807 * clear the processed bit
809 for (cnt = 0; cnt < canvas->txt_cnt; cnt++)
810 _DtCvClearProcessed(lines[cnt]);
813 * initialize the working structure
814 * mark all the lines outside the selection regiion as invalid
817 MarkLinesOutsideBoundary(canvas, next.y, next.x, end->y, end->x);
820 * start the minimum and maximum Y at this location.
826 * is there a line at this location?
828 if (next.line_idx == -1)
831 * find the first selected line within the region.
833 if (FindNextMinY(lines, canvas->txt_cnt, -1, &next.y) == False)
834 processing = False; /* empty of any text */
838 * now find the first line that is on this 'line' and
839 * the number of lines.
842 lineCnt = FindMinX(lines, canvas->txt_cnt, next.y, &next.line_idx);
846 else /* find the number of lines on this 'line' */
847 lineCnt = FindMinX(lines, canvas->txt_cnt, next.y, &cnt);
850 * loop will there are segments to process
852 while (processing == True && result == 0)
855 * process the next line of text.
857 while (result == 0 && lineCnt > 0)
860 * for each segment in this line (that is selected)
861 * create a segment point for it.
863 length = lines[next.line_idx].length;
864 start = lines[next.line_idx].byte_index;
867 * if this is the last line, shorten the length
868 * by the ending index.
870 if (next.line_idx == end->line_idx)
871 length = end->char_idx;
874 * move through the line's segments until we
875 * hit the segment starting the selection
877 pSeg = lines[next.line_idx].seg_ptr;
878 count = next.char_idx;
879 while (NULL != pSeg && 0 < count)
882 * get the byte count of this segment
884 _DtCvGetWidthOfSegment(canvas, pSeg, start, length,
888 * is the byte count of this segment larger than
889 * the starting index of the selection? If not,
890 * the selection is after this segment.
896 pSeg = pSeg->next_disp;
901 start = start + count;
906 while (0 == result && NULL != pSeg && 0 < length)
909 * start with error condition. If the malloc works
910 * the error result gets reset to valid.
913 newPt = (_DtCvSegPts *) malloc (sizeof(_DtCvSegPts));
917 * indicate everything is okay.
922 * get the width of this segment
924 _DtCvGetWidthOfSegment(canvas, pSeg, start, length,
928 * now set the segment point information and add it to the
929 * array of segment points.
931 newPt->offset = start;
933 newPt->segment = pSeg;
935 *ret_segs = (_DtCvSegPts **) _DtCvAddPtrToArray(
938 if (NULL == *ret_segs)
941 pSeg = pSeg->next_disp;
948 * does this line extend below the selection y?
949 * if so, report it as the maximum y.
951 botY = lines[next.line_idx].baseline + lines[next.line_idx].descent;
956 * indicate this line has been processed.
958 _DtCvSetProcessed(lines[next.line_idx]);
964 lineCnt = FindMinX(lines, canvas->txt_cnt, next.y,
971 processing = FindNextMinY(lines,canvas->txt_cnt, -1, &next.y);
972 if (processing == True)
973 lineCnt = FindMinX(lines,canvas->txt_cnt,next.y,&next.line_idx);
978 * if no errors, add a null to the array
982 *ret_segs = (_DtCvSegPts **) _DtCvAddPtrToArray((void **) *ret_segs,
984 if (NULL == *ret_segs)
989 * if errors, free the segment points and return a bad status.
993 if (NULL != *ret_segs)
995 for (lineCnt = 0; NULL != (*ret_segs)[lineCnt]; lineCnt++)
996 free((*ret_segs)[lineCnt]);
999 return _DtCvSTATUS_BAD;
1008 return _DtCvSTATUS_OK;
1011 /******************************************************************************
1012 * Semi-Public Functions
1013 ******************************************************************************/
1014 /*****************************************************************************
1015 * Function: _DtCvDrawAreaWithFlags
1017 *****************************************************************************/
1019 _DtCvDrawAreaWithFlags (
1020 _DtCanvasStruct *canvas,
1021 _DtCvSelectData start,
1022 _DtCvSelectData end,
1023 _DtCvFlags old_flags,
1024 _DtCvFlags new_flags,
1025 _DtCvElemType trav_type,
1026 _DtCvPointer trav_data)
1036 _DtCvUnit superWidth;
1042 _DtCvSegmentI *pSeg;
1043 _DtCvValue lstLinkVis;
1044 _DtCvValue lstWasSuper;
1045 _DtCvValue lstWasSub;
1047 _DtCvFlags flagMask = old_flags | new_flags;
1048 _DtCvFlags endFlag = flagMask & _DtCvTRAVERSAL_END;
1050 _DtCvDspLine *lines = canvas->txt_lst;
1053 * now use the flagMask to determine what else to look for.
1054 * I.e. if flagMask has _DtCvMARK_FLAG set, then it becomes
1055 * set to _DtCvSELECTED_FLAG and visa versa.
1057 flagMask ^= (_DtCvSELECTED_FLAG | _DtCvMARK_FLAG);
1060 * strip the end flag from the other flags
1062 new_flags &= ~(_DtCvTRAVERSAL_END);
1063 old_flags &= ~(_DtCvTRAVERSAL_END);
1065 if (Equal(start, end))
1068 for (i = 0; i < canvas->txt_cnt; i++)
1070 topY = lines[i].baseline - lines[i].ascent;
1071 botY = lines[i].baseline + lines[i].descent;
1073 if (InRegion(topY, botY, start.y, end.y))
1076 * get the start of the text.
1079 lstWasSuper = False;
1082 dstX = _DtCvGetStartXOfLine(&(lines[i]), &pSeg);
1083 startChar = lines[i].byte_index;
1084 count = lines[i].length;
1086 while (pSeg != NULL && _DtCvIsSegNoop(pSeg))
1089 pSeg = pSeg->next_disp;
1093 * advance the starting point
1095 dstX = _DtCvAdvanceXOfLine(canvas, pSeg, dstX,
1096 &lnkInd, &lstLinkVis);
1098 * take into account super/sub scripting
1100 dstX = _DtCvAdjustForSuperSub(canvas, pSeg, dstX, &scriptX,
1101 &superWidth, &superY, &subWidth, &subY,
1102 &lstWasSuper, &lstWasSub);
1105 * set this flag so that the first pass of 'while (cnt > 0)'
1106 * doesn't do it again.
1110 if (_DtCvStraddlesPt(start.y, topY, botY))
1114 * I.E. is this line before the start or after the end?
1116 if (canvas->txt_lst[i].max_x < start.x ||
1117 end.y == start.y && end.x <= dstX )
1121 * does this line start the mark/selection?
1123 if (i == start.line_idx && start.x >= dstX)
1125 int cnt = start.char_idx;
1129 if (trimmed == False)
1132 * advance the starting point
1134 dstX = _DtCvAdvanceXOfLine(canvas, pSeg, dstX,
1135 &lnkInd, &lstLinkVis);
1137 * take into account super/sub scripting
1139 dstX = _DtCvAdjustForSuperSub(canvas,
1140 pSeg, dstX, &scriptX,
1141 &superWidth, &superY, &subWidth, &subY,
1142 &lstWasSuper, &lstWasSub);
1146 * take into account the length of the segment
1148 _DtCvGetWidthOfSegment(canvas, pSeg,
1150 &len, &segWidth, &trimmed);
1154 if (trimmed == False)
1157 pSeg = pSeg->next_disp;
1166 count -= start.char_idx;
1170 * otherwise this line is after the line that starts
1171 * the mark/selection. Stick with its start x.
1176 * does this straddle the end point?
1178 if (_DtCvStraddlesPt(end.y, topY, botY))
1181 * does this start after the end of the mark/selection?
1188 * Does this segment end after the end of the mark/selection?
1189 * If so, trim how much gets highlighted.
1191 if (canvas->txt_lst[i].max_x > end.x)
1192 count -= (lines[i].length - end.char_idx);
1196 * while there is something to draw (un)mark/selected.
1198 old_flags = old_flags | _DtCvMARK_BEGIN;
1199 new_flags = new_flags | _DtCvMARK_BEGIN;
1203 * the original count to render
1208 * check for other marks and selection.
1210 _DtCvCheckLineMarks(canvas, i, startChar - lines[i].byte_index,
1211 count, dstX, flagMask,
1212 &len, &old_flags, &new_flags);
1215 * if this is the last segment(s) of the (un)mark/selection
1216 * set the end flags.
1220 new_flags |= (endFlag | _DtCvLINK_END | _DtCvMARK_END);
1221 old_flags |= (endFlag | _DtCvLINK_END | _DtCvMARK_END);
1225 * draw the segments that are marked/unmarked.
1227 dstX = _DtCvDrawSegments(canvas, lines[i],
1228 pSeg, startChar , len, &lnkInd,
1229 dstX, dstX, &scriptX,
1230 &superWidth, &superY, &subWidth, &subY,
1231 &lstWasSub, &lstWasSuper,
1232 &lstLinkVis, old_flags, new_flags,
1233 trav_type, trav_data);
1235 * modify the count by the length processed
1240 * did this do the entire length? If not, set the
1241 * indexes ahead and do again.
1244 _DtCvSkipLineChars(canvas, pSeg, startChar , count + len,
1245 len, &startChar , &pSeg);
1248 * strip the any begin flags.
1250 _DtCvRemoveBeginFlags(old_flags);
1251 _DtCvRemoveBeginFlags(new_flags);
1257 /*****************************************************************************
1258 * Function: _DtCanvasGetSelectionPoints()
1260 * Purpose: Retrieve the segments making up the selection.
1262 *****************************************************************************/
1265 _DtCanvasStruct *canvas,
1266 _DtCvPointInfo ***ret_info)
1272 for (i = 0; i < canvas->mark_cnt; i++)
1274 _DtCvPointInfo *nxtInfo;
1277 * allocate mark information structure
1279 nxtInfo = (_DtCvPointInfo *) malloc (sizeof(_DtCvPointInfo));
1280 if (NULL == nxtInfo)
1281 return _DtCvSTATUS_BAD;
1283 nxtInfo->client_data = canvas->marks[i].client_data;
1285 if (_DtCvSTATUS_BAD == GetSegsInArea(canvas, &(canvas->marks[i].beg),
1286 &(canvas->marks[i].end),
1289 return _DtCvSTATUS_BAD;
1291 *ret_info = (_DtCvPointInfo **) _DtCvAddPtrToArray((void **) *ret_info,
1293 if (NULL == *ret_info)
1294 return _DtCvSTATUS_BAD;
1297 return _DtCvSTATUS_OK;
1300 /******************************************************************************
1302 ******************************************************************************/
1303 /*****************************************************************************
1304 * Function: _DtCanvasGetSelection()
1306 * Purpose: Indicate the end point for a selection.
1308 *****************************************************************************/
1310 _DtCanvasGetSelection (
1311 _DtCvHandle canvas_handle,
1313 _DtCvPointer *ret_select)
1315 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1318 return(GetSelectedText(canvas, canvas->select_start, canvas->select_end,
1322 /*****************************************************************************
1323 * Function: _DtCanvasProcessSelection()
1325 * Purpose: Indicate an new point for a selection.
1327 *****************************************************************************/
1329 _DtCanvasProcessSelection (
1330 _DtCvHandle canvas_handle,
1333 _DtCvSelectMode mode)
1336 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1337 _DtCvSelectData temp;
1341 case _DtCvSELECTION_CLEAR:
1342 CheckAndSwitchPoints(&(canvas->select_start),
1343 &(canvas->select_end));
1345 case _DtCvSELECTION_START:
1346 _DtCvDrawAreaWithFlags(canvas, canvas->select_start,
1348 _DtCvSELECTED_FLAG, 0,
1349 _DtCvBAD_TYPE, NULL);
1351 canvas->select_start = defaultSelect;
1352 if (mode == _DtCvSELECTION_START)
1353 SearchForClosestLine(canvas, x, y, &(canvas->select_start));
1355 canvas->select_end = canvas->select_start;
1358 case _DtCvSELECTION_END:
1359 case _DtCvSELECTION_UPDATE:
1360 SearchForClosestLine(canvas, x, y, &temp);
1362 AdjustSelection (canvas, temp);
1363 if (mode == _DtCvSELECTION_END)
1364 CheckAndSwitchPoints(&(canvas->select_start),
1365 &(canvas->select_end));
1370 /*****************************************************************************
1371 * Function: _DtCanvasGetSelectionPoints()
1373 * Purpose: Retrieve the segments making up the selection.
1375 *****************************************************************************/
1377 _DtCanvasGetSelectionPoints (
1378 _DtCvHandle canvas_handle,
1379 _DtCvSegPts ***ret_segs,
1383 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1385 return (GetSegsInArea(canvas, &(canvas->select_start),
1386 &(canvas->select_end), ret_segs, ret_y1, ret_y2));
1389 /*****************************************************************************
1390 * Function: _DtCanvasActivatePts()
1392 * Purpose: Activate the points given.
1394 *****************************************************************************/
1396 _DtCanvasActivatePts (
1397 _DtCvHandle canvas_handle,
1399 _DtCvPointInfo *info,
1404 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1405 _DtCvSelectData startSel = defaultSelect;
1406 _DtCvSelectData endSel = defaultSelect;
1408 _DtCvSegmentI *firstSeg;
1410 #define REQUIRE_SEGS \
1411 (_DtCvACTIVATE_MARK | _DtCvACTIVATE_SELECTION)
1413 * check to see if there is anything to do
1416 return _DtCvSTATUS_NONE;
1418 if ((mask & _DtCvACTIVATE_MARK) && (mask & _DtCvDEACTIVATE))
1419 return _DtCvSTATUS_BAD;
1422 * Convert the segments into starting and ending positions.
1424 if (((mask & _DtCvDEACTIVATE) && NULL == info->client_data)
1425 || (mask & REQUIRE_SEGS))
1427 if (NULL == info || NULL == info->segs ||
1428 _DtCvSTATUS_BAD == _DtCvCvtSegsToPts(canvas, info->segs,
1430 ret_y1, ret_y2, &firstSeg))
1431 return _DtCvSTATUS_BAD;
1435 * Activate as a selection
1437 if (mask & _DtCvACTIVATE_SELECTION)
1439 _DtCanvasProcessSelection (canvas_handle, 0, 0, _DtCvSELECTION_CLEAR);
1441 canvas->select_start = startSel;
1442 canvas->select_end = endSel;
1444 _DtCvDrawAreaWithFlags (canvas, startSel, endSel,
1445 0, _DtCvSELECTED_FLAG,
1446 _DtCvBAD_TYPE, NULL);
1450 * Activate as a mark
1452 if (mask & _DtCvACTIVATE_MARK)
1460 markIdx = _DtCvAddToMarkList(canvas, info->client_data,
1461 _DtCvIsMarkMaskOn(mask), &startSel, &endSel);
1463 return _DtCvSTATUS_BAD;
1466 * now put the mark in the traversal list and merge it into the
1469 travIdx = _DtCvGetNextTravEntry(canvas);
1471 || 0 != _DtCvSetTravEntryInfo(canvas, travIdx,
1472 _DtCvTraversalMark, firstSeg,
1474 || 0 != _DtCvCalcMarkPos(canvas, markIdx,
1475 &x, &y, &width, &height)
1476 || 0 != _DtCvSetTravEntryPos(canvas, travIdx,
1477 x, y, width, height))
1478 return _DtCvSTATUS_BAD;
1480 _DtCvSortTraversalList(canvas, _DtCvTRUE);
1483 * draw these segments marked.
1485 flag = _DtCvMARK_FLAG;
1486 if (_DtCvTRUE == canvas->marks[markIdx].on)
1487 flag |= _DtCvMARK_ON;
1489 _DtCvDrawAreaWithFlags (canvas, startSel, endSel,
1491 _DtCvBAD_TYPE, NULL);
1495 * Clear the mark flag.
1497 else if (mask & _DtCvDEACTIVATE)
1502 * is there anything to deacivate?
1504 if (NULL == canvas->marks || 0 == canvas->mark_cnt)
1505 return _DtCvSTATUS_BAD;
1508 * was client data specified? If so, then look for it and ignore
1512 if (NULL != info->client_data)
1514 while (markIdx < canvas->mark_cnt &&
1515 canvas->marks[markIdx].client_data != info->client_data)
1519 * initialize the selection points
1521 if (markIdx < canvas->mark_cnt)
1523 startSel = canvas->marks[markIdx].beg;
1524 endSel = canvas->marks[markIdx].end;
1528 * look for the marked set using the segments.
1532 while (markIdx < canvas->mark_cnt
1533 && startSel.line_idx != canvas->marks[markIdx].beg.line_idx
1534 && startSel.char_idx != canvas->marks[markIdx].beg.char_idx
1535 && endSel.line_idx != canvas->marks[markIdx].end.line_idx
1536 && endSel.line_idx != canvas->marks[markIdx].end.char_idx)
1540 if (markIdx >= canvas->mark_cnt)
1541 return _DtCvSTATUS_BAD;
1544 * draw these segments unmarked.
1546 flag = _DtCvMARK_FLAG;
1547 if (_DtCvTRUE == canvas->marks[markIdx].on)
1548 flag |= _DtCvMARK_ON;
1550 canvas->marks[markIdx].on = _DtCvFALSE;
1551 _DtCvDrawAreaWithFlags (canvas, startSel, endSel, flag, 0,
1552 _DtCvBAD_TYPE, NULL);
1555 * remove the mark from the traversal list
1557 * first find the traversal entry of the mark and adjust any
1558 * traversal mark index values to reflect that the mark
1559 * list is about to shrink by 1.
1561 for (travIdx = 0; _DtCvTraversalMark != canvas->trav_lst[travIdx].type
1562 || markIdx != canvas->trav_lst[travIdx].idx; travIdx++)
1565 * is this mark after the one being removed?
1566 * if so, decrease its index because it's about to move.
1568 if (_DtCvTraversalMark == canvas->trav_lst[travIdx].type &&
1569 markIdx < canvas->trav_lst[travIdx].idx)
1570 canvas->trav_lst[travIdx].idx--;
1574 * move the list of traversal entries to eliminate the mark entry.
1576 while (travIdx + 1 < canvas->trav_cnt)
1578 canvas->trav_lst[travIdx] = canvas->trav_lst[travIdx + 1];
1581 * is this a mark after the one being removed?
1582 * if so, decrease it's index because it's about to move.
1584 if (_DtCvTraversalMark == canvas->trav_lst[travIdx].type &&
1585 markIdx < canvas->trav_lst[travIdx].idx)
1586 canvas->trav_lst[travIdx].idx--;
1592 * update the traversal count and back up to the previous traversal
1593 * if the mark was at the end of the traversal list.
1596 if (canvas->cur_trav >= canvas->trav_cnt)
1600 * move the list of marks up
1602 while (markIdx + 1 < canvas->mark_cnt)
1604 canvas->marks[markIdx] = canvas->marks[markIdx + 1];
1610 else if ((_DtCvACTIVATE_MARK_ON | _DtCvACTIVATE_MARK_OFF) & mask)
1613 if (NULL != info && NULL != info->client_data)
1615 while (markIdx < canvas->mark_cnt &&
1616 canvas->marks[markIdx].client_data != info->client_data)
1620 * was a mark with this client data found?
1622 if (markIdx >= canvas->mark_cnt)
1623 return _DtCvSTATUS_BAD;
1628 * are there any traversals? Is the current one sitting on a mark?
1630 if (0 == canvas->trav_cnt || -1 == canvas->cur_trav ||
1631 _DtCvTraversalMark != canvas->trav_lst[canvas->cur_trav].type)
1632 return _DtCvSTATUS_BAD;
1635 * get the mark index
1637 markIdx = canvas->trav_lst[canvas->cur_trav].idx;
1641 * is this different than what it is set at now? If not, do nothing.
1643 if (_DtCvIsMarkMaskOn(mask) == canvas->marks[markIdx].on)
1644 return _DtCvSTATUS_NONE;
1647 * set to mask value.
1649 canvas->marks[markIdx].on = _DtCvIsMarkMaskOn(mask);
1652 * set the flags correctly.
1654 flag = _DtCvMARK_FLAG;
1655 if (_DtCvTRUE == canvas->marks[markIdx].on)
1656 flag |= _DtCvMARK_ON;
1657 if (_DtCvTRUE == canvas->trav_on &&
1658 markIdx == canvas->trav_lst[canvas->cur_trav].idx)
1659 flag |= _DtCvTRAVERSAL_FLAG;
1662 * draw the mark opposite what it was
1664 _DtCvDrawAreaWithFlags (canvas, canvas->marks[markIdx].beg,
1665 canvas->marks[markIdx].end,
1666 (flag ^ _DtCvMARK_ON), flag,
1667 _DtCvBAD_TYPE, NULL);
1670 return _DtCvSTATUS_OK;
1673 /*****************************************************************************
1674 * Function: _DtCanvasGetMarkPositions()
1676 * Purpose: Return the position in the canvas of the marks.
1678 *****************************************************************************/
1680 _DtCanvasGetMarkPositions (
1681 _DtCvHandle canvas_handle,
1682 _DtCvMarkPos ***ret_pos)
1685 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1686 _DtCvMarkPos *nextPos;
1687 _DtCvMarkData *markLst = canvas->marks;
1691 if (0 == canvas->mark_cnt)
1692 return _DtCvSTATUS_NONE;
1694 for (i = 0; i < canvas->mark_cnt; i++, markLst++)
1697 * malloc memory for the information
1699 nextPos = (_DtCvMarkPos *) malloc (sizeof(_DtCvMarkPos));
1700 if (NULL == nextPos)
1701 return _DtCvSTATUS_BAD;
1704 * client data and baselines
1706 nextPos->client_data = markLst->client_data;
1707 nextPos->baseline1 = canvas->txt_lst[markLst->beg.line_idx].baseline;
1708 nextPos->baseline2 = canvas->txt_lst[markLst->end.line_idx].baseline;
1713 nextPos->x1 = markLst->beg.x;
1714 nextPos->y1 = nextPos->baseline1 -
1715 canvas->txt_lst[markLst->beg.line_idx].ascent;
1718 * bottom right corner
1720 nextPos->x2 = markLst->end.x;
1721 nextPos->y2 = nextPos->baseline2 +
1722 canvas->txt_lst[markLst->end.line_idx].descent;
1724 *ret_pos = (_DtCvMarkPos **) _DtCvAddPtrToArray((void **) *ret_pos,
1726 if (NULL == *ret_pos)
1727 return _DtCvSTATUS_BAD;
1730 return _DtCvSTATUS_OK;