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"
61 #include "VirtFuncsI.h"
66 /******** Private Function Declarations ********/
67 static void AdjustSelection (
68 _DtCanvasStruct *canvas,
69 _DtCvSelectData next);
70 static int GetSelectedText(
71 _DtCanvasStruct *canvas,
72 _DtCvSelectData start,
75 _DtCvPointer *ret_data);
76 /******** End Private Function Declarations ********/
78 /******** Private Defines ********/
80 /******** End Private Defines ********/
82 /******** Macros ********/
83 #define Equal(a,b) (a.y == b.y && a.x == b.x)
84 #define LessThan(a,b) ((a.y < b.y) || (a.y == b.y && a.x < b.x))
85 #define GreaterThan(a,b) ((a.y > b.y) || (a.y == b.y && a.x > b.x))
86 #define LessThanEq(a,b) (Equal(a,b) || LessThan(a,b))
87 #define GreaterThanEq(a,b) (Equal(a,b) || GreaterThan(a,b))
89 #define InRegion(top,bot,min,max) ((min) <= (bot) && (top) <= (max))
91 /******** End Macros ********/
93 /******** Private Variable Declarations ********/
94 static const _DtCvSelectData defaultSelect = { -1, -1, -1, -1};
96 /******** End Private Variable Declarations ********/
98 /******************************************************************************
100 ******************************************************************************/
101 /******************************************************************************
102 * Function: StartXOfLine
104 * Purpose: Determine the start of a line, takes into consideration
105 * the traversal and link before values. The 'x' returned is
106 * exactly where the text/graphic is to be placed on the canvas.
107 *****************************************************************************/
110 _DtCanvasStruct *canvas,
113 _DtCvValue lastLinkVisible = FALSE;
118 xPos = _DtCvGetStartXOfLine(&line, &pSeg);
119 return (_DtCvAdvanceXOfLine( canvas, pSeg, xPos,
120 &lnkInd, &lastLinkVisible));
122 } /* End StartXOfLine */
124 /*****************************************************************************
125 * Function: SearchForClosestLine
127 * Purpose: Initializes the 'new' structure with information indicating
128 * what line is closest to the target_y.
129 * next->y Set to target_y if no line straddles it.
130 * Otherwise, it will be set to the minimum
131 * y of all lines straddling the target_y.
132 * next->x Set to target_x if no line straddles
133 * target_y or if target_x is before the
134 * first line straddling target_y.
135 * next->line_idx Set to -1 if no line straddles target_y.
136 * Otherwise, set to the first line that
137 * straddles target_x or is the minimum x
138 * that is greater than target_x of all the
139 * lines straddling target_x.
140 * next->char_idx Set to -1 if no straddles target_y.
141 * Otherwise, set to the character that
142 * resides at target_x if target_x is in
143 * the middle of the line. Set to zero if
144 * target_x is before the line, and set to
145 * the line count if target_x is after the
148 *****************************************************************************/
150 SearchForClosestLine (
151 _DtCanvasStruct *canvas,
154 _DtCvSelectData *next)
162 _DtCvDspLine *lines = canvas->txt_lst;
164 *next = defaultSelect;
165 for (i = 0; i < canvas->txt_cnt; i++)
168 * get the maximum y of the line
169 * if it straddles the target y, process it.
171 lineY = lines[i].baseline + lines[i].descent;
172 if (_DtCvStraddlesPt(target_y,lines[i].baseline-lines[i].ascent,lineY))
175 * Is this the minimum y of all the maximum y values of the
176 * line straddling the target y?
178 if (next->y == -1 || next->y > lineY)
182 * Get the maximum X position of the line.
183 * If this is the maximum X of all the lines straddling
184 * the target y, remember it.
186 endX = canvas->txt_lst[i].max_x;
187 if (maxX < endX && endX < target_x)
194 * Does this line straddle the x?
196 begX = StartXOfLine(canvas, lines[i]);
197 if (_DtCvStraddlesPt(target_x, begX, endX))
200 next->char_idx = _DtCvGetCharIdx(canvas,lines[i],target_x);
206 * remember what the target x was for this line. If the target x is
207 * less than the start of the line, then the selection process will
208 * highlight the space before the line. If its in the middle, it
209 * will just highlight starting at the character. If it's after the
210 * end, the rest will be cut off at the end of the line.
215 * If we found a line straddling the target y, but it does not
216 * straddle the target_x, check max x for the correct info.
218 if (next->line_idx == -1 && maxX > -1)
220 next->line_idx = maxI;
221 next->char_idx = lines[maxI].length;
225 * didn't find a line straddling the target_y, set y.
231 /*****************************************************************************
232 * Function: MarkLinesOutsideBoundary
234 *****************************************************************************/
236 MarkLinesOutsideBoundary (
237 _DtCanvasStruct *canvas,
246 _DtCvDspLine *lines = canvas->txt_lst;
248 for (i = 0; i < canvas->txt_cnt; i++)
250 maxY = lines[i].baseline + lines[i].descent;
251 minY = lines[i].baseline - lines[i].ascent;
254 * is this line outside the boundary?
255 * If so, mark it so it's not processed.
257 if (maxY < top_y || minY > bot_y )
258 _DtCvSetProcessed(lines[i]);
263 * does it straddle the top?
265 if (_DtCvStraddlesPt(top_y, minY, maxY))
268 * Does it begin before the selection?
269 * If so, mark it so it's not processed.
271 if (canvas->txt_lst[i].max_x <= top_x)
272 _DtCvSetProcessed(lines[i]);
276 * does it straddle the bottom?
278 if (_DtCvStraddlesPt(bot_y, minY, maxY))
281 * Does it start after the selection?
282 * If so, mark it so it's not processed.
284 if (StartXOfLine(canvas, lines[i]) >= bot_x)
285 _DtCvSetProcessed(lines[i]);
291 /*****************************************************************************
292 * Function: AdjustSelection
294 *****************************************************************************/
297 _DtCanvasStruct *canvas,
298 _DtCvSelectData next)
300 _DtCvSelectData start = canvas->select_start;
301 _DtCvSelectData end = canvas->select_end;
303 if (!(Equal(next, end)))
305 if (next.line_idx != -1 && next.line_idx == canvas->select_end.line_idx
307 next.char_idx != -1 && next.char_idx == canvas->select_end.char_idx)
310 if (GreaterThan(next, end))
312 if (LessThanEq(start, end))
313 _DtCvDrawAreaWithFlags (canvas, end, next,
314 0, _DtCvSELECTED_FLAG,
315 _DtCvBAD_TYPE, NULL);
317 else if (GreaterThanEq(start, next))
318 _DtCvDrawAreaWithFlags (canvas, end, next,
319 _DtCvSELECTED_FLAG, 0,
320 _DtCvBAD_TYPE, NULL);
322 else /* end < start < next */
324 _DtCvDrawAreaWithFlags (canvas, end , start,
325 _DtCvSELECTED_FLAG, 0,
326 _DtCvBAD_TYPE, NULL);
327 _DtCvDrawAreaWithFlags (canvas, start, next ,
328 0, _DtCvSELECTED_FLAG,
329 _DtCvBAD_TYPE, NULL);
332 else /* if (next < end) */
334 if (LessThanEq(start, next))
335 _DtCvDrawAreaWithFlags (canvas, next, end,
336 _DtCvSELECTED_FLAG, 0,
337 _DtCvBAD_TYPE, NULL);
339 else if (GreaterThanEq(start, end))
340 _DtCvDrawAreaWithFlags (canvas, next, end,
341 0, _DtCvSELECTED_FLAG,
342 _DtCvBAD_TYPE, NULL);
344 else /* next < start < end */
346 _DtCvDrawAreaWithFlags (canvas, start, end ,
347 _DtCvSELECTED_FLAG, 0,
348 _DtCvBAD_TYPE, NULL);
349 _DtCvDrawAreaWithFlags (canvas, next , start,
350 0, _DtCvSELECTED_FLAG,
351 _DtCvBAD_TYPE, NULL);
356 canvas->select_end = next;
359 /*****************************************************************************
360 * Function: SkipOtherLines
362 *****************************************************************************/
371 while (idx < max_cnt && _DtCvIsNotProcessed(lines[idx]) &&
372 lines[idx].baseline - lines[idx].ascent > target_y)
378 /*****************************************************************************
379 * Function: CheckAndSwitchPoints
381 *****************************************************************************/
383 CheckAndSwitchPoints(
384 _DtCvSelectData *pt1,
385 _DtCvSelectData *pt2)
387 _DtCvSelectData temp;
389 if (pt1->y > pt2->y || (pt1->y == pt2->y && pt1->x > pt2->x))
397 /*****************************************************************************
398 * Function: AddSegmentToData
400 *****************************************************************************/
403 _DtCanvasStruct *canvas,
411 _DtCvPointer *ret_data)
413 _DtCvDspLine line = canvas->txt_lst[line_idx];
414 int result = _DtCvSTATUS_OK;
415 int count = line.length;
416 int start = line.byte_index;
421 _DtCvUnit xPos = line.text_x;
423 _DtCvSegmentI *pSeg = line.seg_ptr;
425 _DtCvValue done = False;
426 _DtCvValue lastLinkVisible = FALSE;
427 _DtCvStringInfo strInfo;
429 xPos = _DtCvGetStartXOfLine(&line, &pSeg);
431 while (done == False && char_idx)
434 * advance past the link and traversal info
436 xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos,
437 &lnkInd, &lastLinkVisible);
440 * advance the pointer by the width
442 _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
443 &cnt, &segWidth, NULL);
447 pSeg = pSeg->next_disp;
454 _DtCvGetWidthOfSegment(canvas, pSeg, start, char_idx,
455 &cnt, &segWidth, NULL);
466 while (_DtCvSTATUS_OK == result && pSeg != NULL && copy_cnt > 0)
469 * advance past the link and traversal info
471 xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos,
472 &lnkInd, &lastLinkVisible);
474 switch (_DtCvPrimaryTypeOfSeg(pSeg))
478 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
479 _DtCvIsSegWideChar(pSeg), start);
480 len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
485 segWidth = _DtCvGetStringWidth(canvas, pSeg, pChar, len);
489 strInfo.string = pChar;
490 strInfo.byte_len = len;
491 strInfo.wc = _DtCvIsSegWideChar(pSeg);
492 strInfo.font_ptr = _DtCvFontOfStringSeg(pSeg);
494 if (canvas->virt_functions.build_selection != NULL)
495 result = (*(canvas->virt_functions.build_selection))(
503 (_DtCvPointer) &strInfo);
505 if (_DtCvSTATUS_OK == result)
507 if (line.baseline + line.descent > *ret_y)
508 *ret_y = line.baseline + line.descent;
509 start_x = xPos + segWidth;
511 else if (_DtCvSTATUS_NONE == result)
512 result = _DtCvSTATUS_OK;
523 if (canvas->virt_functions.build_selection != NULL)
524 result = (*(canvas->virt_functions.build_selection))(
530 _DtCvWidthOfRegionSeg(pSeg),
532 _DtCvInfoOfRegionSeg(pSeg));
534 if (_DtCvSTATUS_OK == result)
536 if (line.baseline + line.descent > *ret_y)
537 *ret_y = line.baseline + line.descent;
538 start_x = xPos + segWidth;
540 else if (_DtCvSTATUS_NONE == result)
541 result = _DtCvSTATUS_OK;
544 xPos += _DtCvWidthOfRegionSeg(pSeg);
547 pSeg = pSeg->next_disp;
550 if (result != _DtCvSTATUS_OK)
556 /*****************************************************************************
557 * Function: BuildLine
559 *****************************************************************************/
562 _DtCanvasStruct *canvas,
572 _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)
699 int txtCnt = canvas->txt_cnt;
701 _DtCvValue processing = True;
702 _DtCvDspLine *lines = canvas->txt_lst;
704 for (i = 0; i < txtCnt; i++)
705 _DtCvClearProcessed(lines[i]);
707 MarkLinesOutsideBoundary(canvas, next.y, next.x, end.y, end.x);
710 if (next.line_idx == -1)
713 * find the first selected line
715 if (FindNextMinY(lines, txtCnt, -1, &next.y) == False)
719 lineCnt = FindMinX(lines, txtCnt, next.y, &next.line_idx);
723 lineCnt = FindMinX(lines, txtCnt, next.y, &junk);
725 while (processing == True && result == 0)
728 * process the next line of text.
733 cpyCnt = lines[next.line_idx].length - next.char_idx;
734 if (next.line_idx == end.line_idx)
735 cpyCnt = cpyCnt - lines[next.line_idx].length + end.char_idx;
736 else if (lineCnt == 1)
737 endFlag = _DtCvEND_OF_LINE;
739 result = BuildLine(canvas, mask, maxY, next.x,
740 next.line_idx, next.char_idx,
742 &next.x, &botY, ret_data);
748 lineCnt = FindMinX(lines, txtCnt, next.y, &next.line_idx);
750 } while (result == 0 && lineCnt > 0);
755 processing = FindNextMinY(lines, txtCnt, -1, &next.y);
756 if (processing == True)
757 lineCnt = FindMinX(lines, txtCnt, next.y, &next.line_idx);
763 } /* End GetSelectedText */
765 /*****************************************************************************
766 * Function: GetSegsInArea()
768 * Purpose: Retrieve the segments making up the selection.
770 *****************************************************************************/
773 _DtCanvasStruct *canvas,
774 _DtCvSelectData *beg,
775 _DtCvSelectData *end,
776 _DtCvSegPts ***ret_segs,
786 _DtCvValue processing = True;
790 _DtCvSelectData next;
793 _DtCvDspLine *lines = canvas->txt_lst;
798 return _DtCvSTATUS_NONE;
801 * make sure the selection points are in the correct order.
803 CheckAndSwitchPoints(beg, end);
806 * clear the processed bit
808 for (cnt = 0; cnt < canvas->txt_cnt; cnt++)
809 _DtCvClearProcessed(lines[cnt]);
812 * initialize the working structure
813 * mark all the lines outside the selection regiion as invalid
816 MarkLinesOutsideBoundary(canvas, next.y, next.x, end->y, end->x);
819 * start the minimum and maximum Y at this location.
825 * is there a line at this location?
827 if (next.line_idx == -1)
830 * find the first selected line within the region.
832 if (FindNextMinY(lines, canvas->txt_cnt, -1, &next.y) == False)
833 processing = False; /* empty of any text */
837 * now find the first line that is on this 'line' and
838 * the number of lines.
841 lineCnt = FindMinX(lines, canvas->txt_cnt, next.y, &next.line_idx);
845 else /* find the number of lines on this 'line' */
846 lineCnt = FindMinX(lines, canvas->txt_cnt, next.y, &cnt);
849 * loop will there are segments to process
851 while (processing == True && result == 0)
854 * process the next line of text.
856 while (result == 0 && lineCnt > 0)
859 * for each segment in this line (that is selected)
860 * create a segment point for it.
862 length = lines[next.line_idx].length;
863 start = lines[next.line_idx].byte_index;
866 * if this is the last line, shorten the length
867 * by the ending index.
869 if (next.line_idx == end->line_idx)
870 length = end->char_idx;
873 * move through the line's segments until we
874 * hit the segment starting the selection
876 pSeg = lines[next.line_idx].seg_ptr;
877 count = next.char_idx;
878 while (NULL != pSeg && 0 < count)
881 * get the byte count of this segment
883 _DtCvGetWidthOfSegment(canvas, pSeg, start, length,
887 * is the byte count of this segment larger than
888 * the starting index of the selection? If not,
889 * the selection is after this segment.
895 pSeg = pSeg->next_disp;
900 start = start + count;
905 while (0 == result && NULL != pSeg && 0 < length)
908 * start with error condition. If the malloc works
909 * the error result gets reset to valid.
912 newPt = (_DtCvSegPts *) malloc (sizeof(_DtCvSegPts));
916 * indicate everything is okay.
921 * get the width of this segment
923 _DtCvGetWidthOfSegment(canvas, pSeg, start, length,
927 * now set the segment point information and add it to the
928 * array of segment points.
930 newPt->offset = start;
932 newPt->segment = pSeg;
934 *ret_segs = (_DtCvSegPts **) _DtCvAddPtrToArray(
937 if (NULL == *ret_segs)
940 pSeg = pSeg->next_disp;
947 * does this line extend below the selection y?
948 * if so, report it as the maximum y.
950 botY = lines[next.line_idx].baseline + lines[next.line_idx].descent;
955 * indicate this line has been processed.
957 _DtCvSetProcessed(lines[next.line_idx]);
963 lineCnt = FindMinX(lines, canvas->txt_cnt, next.y,
970 processing = FindNextMinY(lines,canvas->txt_cnt, -1, &next.y);
971 if (processing == True)
972 lineCnt = FindMinX(lines,canvas->txt_cnt,next.y,&next.line_idx);
977 * if no errors, add a null to the array
981 *ret_segs = (_DtCvSegPts **) _DtCvAddPtrToArray((void **) *ret_segs,
983 if (NULL == *ret_segs)
988 * if errors, free the segment points and return a bad status.
992 if (NULL != *ret_segs)
994 for (lineCnt = 0; NULL != (*ret_segs)[lineCnt]; lineCnt++)
995 free((*ret_segs)[lineCnt]);
998 return _DtCvSTATUS_BAD;
1007 return _DtCvSTATUS_OK;
1010 /******************************************************************************
1011 * Semi-Public Functions
1012 ******************************************************************************/
1013 /*****************************************************************************
1014 * Function: _DtCvDrawAreaWithFlags
1016 *****************************************************************************/
1018 _DtCvDrawAreaWithFlags (
1019 _DtCanvasStruct *canvas,
1020 _DtCvSelectData start,
1021 _DtCvSelectData end,
1022 _DtCvFlags old_flags,
1023 _DtCvFlags new_flags,
1024 _DtCvElemType trav_type,
1025 _DtCvPointer trav_data)
1035 _DtCvUnit superWidth;
1041 _DtCvSegmentI *pSeg;
1042 _DtCvValue lstLinkVis;
1043 _DtCvValue lstWasSuper;
1044 _DtCvValue lstWasSub;
1046 _DtCvFlags flagMask = old_flags | new_flags;
1047 _DtCvFlags endFlag = flagMask & _DtCvTRAVERSAL_END;
1049 _DtCvDspLine *lines = canvas->txt_lst;
1052 * now use the flagMask to determine what else to look for.
1053 * I.e. if flagMask has _DtCvMARK_FLAG set, then it becomes
1054 * set to _DtCvSELECTED_FLAG and visa versa.
1056 flagMask ^= (_DtCvSELECTED_FLAG | _DtCvMARK_FLAG);
1059 * strip the end flag from the other flags
1061 new_flags &= ~(_DtCvTRAVERSAL_END);
1062 old_flags &= ~(_DtCvTRAVERSAL_END);
1064 if (Equal(start, end))
1067 for (i = 0; i < canvas->txt_cnt; i++)
1069 topY = lines[i].baseline - lines[i].ascent;
1070 botY = lines[i].baseline + lines[i].descent;
1072 if (InRegion(topY, botY, start.y, end.y))
1075 * get the start of the text.
1078 lstWasSuper = False;
1081 dstX = _DtCvGetStartXOfLine(&(lines[i]), &pSeg);
1082 startChar = lines[i].byte_index;
1083 count = lines[i].length;
1085 while (pSeg != NULL && _DtCvIsSegNoop(pSeg))
1088 pSeg = pSeg->next_disp;
1092 * advance the starting point
1094 dstX = _DtCvAdvanceXOfLine(canvas, pSeg, dstX,
1095 &lnkInd, &lstLinkVis);
1097 * take into account super/sub scripting
1099 dstX = _DtCvAdjustForSuperSub(canvas, pSeg, dstX, &scriptX,
1100 &superWidth, &superY, &subWidth, &subY,
1101 &lstWasSuper, &lstWasSub);
1104 * set this flag so that the first pass of 'while (cnt > 0)'
1105 * doesn't do it again.
1109 if (_DtCvStraddlesPt(start.y, topY, botY))
1113 * I.E. is this line before the start or after the end?
1115 if (canvas->txt_lst[i].max_x < start.x ||
1116 (end.y == start.y && end.x <= dstX) )
1120 * does this line start the mark/selection?
1122 if (i == start.line_idx && start.x >= dstX)
1124 int cnt = start.char_idx;
1128 if (trimmed == False)
1131 * advance the starting point
1133 dstX = _DtCvAdvanceXOfLine(canvas, pSeg, dstX,
1134 &lnkInd, &lstLinkVis);
1136 * take into account super/sub scripting
1138 dstX = _DtCvAdjustForSuperSub(canvas,
1139 pSeg, dstX, &scriptX,
1140 &superWidth, &superY, &subWidth, &subY,
1141 &lstWasSuper, &lstWasSub);
1145 * take into account the length of the segment
1147 _DtCvGetWidthOfSegment(canvas, pSeg,
1149 &len, &segWidth, &trimmed);
1153 if (trimmed == False)
1156 pSeg = pSeg->next_disp;
1165 count -= start.char_idx;
1169 * otherwise this line is after the line that starts
1170 * the mark/selection. Stick with its start x.
1175 * does this straddle the end point?
1177 if (_DtCvStraddlesPt(end.y, topY, botY))
1180 * does this start after the end of the mark/selection?
1187 * Does this segment end after the end of the mark/selection?
1188 * If so, trim how much gets highlighted.
1190 if (canvas->txt_lst[i].max_x > end.x)
1191 count -= (lines[i].length - end.char_idx);
1195 * while there is something to draw (un)mark/selected.
1197 old_flags = old_flags | _DtCvMARK_BEGIN;
1198 new_flags = new_flags | _DtCvMARK_BEGIN;
1202 * the original count to render
1207 * check for other marks and selection.
1209 _DtCvCheckLineMarks(canvas, i, startChar - lines[i].byte_index,
1210 count, dstX, flagMask,
1211 &len, &old_flags, &new_flags);
1214 * if this is the last segment(s) of the (un)mark/selection
1215 * set the end flags.
1219 new_flags |= (endFlag | _DtCvLINK_END | _DtCvMARK_END);
1220 old_flags |= (endFlag | _DtCvLINK_END | _DtCvMARK_END);
1224 * draw the segments that are marked/unmarked.
1226 dstX = _DtCvDrawSegments(canvas, lines[i],
1227 pSeg, startChar , len, &lnkInd,
1228 dstX, dstX, &scriptX,
1229 &superWidth, &superY, &subWidth, &subY,
1230 &lstWasSub, &lstWasSuper,
1231 &lstLinkVis, old_flags, new_flags,
1232 trav_type, trav_data);
1234 * modify the count by the length processed
1239 * did this do the entire length? If not, set the
1240 * indexes ahead and do again.
1243 _DtCvSkipLineChars(canvas, pSeg, startChar , count + len,
1244 len, &startChar , &pSeg);
1247 * strip the any begin flags.
1249 _DtCvRemoveBeginFlags(old_flags);
1250 _DtCvRemoveBeginFlags(new_flags);
1256 /*****************************************************************************
1257 * Function: _DtCanvasGetSelectionPoints()
1259 * Purpose: Retrieve the segments making up the selection.
1261 *****************************************************************************/
1264 _DtCanvasStruct *canvas,
1265 _DtCvPointInfo ***ret_info)
1271 for (i = 0; i < canvas->mark_cnt; i++)
1273 _DtCvPointInfo *nxtInfo;
1276 * allocate mark information structure
1278 nxtInfo = (_DtCvPointInfo *) malloc (sizeof(_DtCvPointInfo));
1279 if (NULL == nxtInfo)
1280 return _DtCvSTATUS_BAD;
1282 nxtInfo->client_data = canvas->marks[i].client_data;
1284 if (_DtCvSTATUS_BAD == GetSegsInArea(canvas, &(canvas->marks[i].beg),
1285 &(canvas->marks[i].end),
1288 return _DtCvSTATUS_BAD;
1290 *ret_info = (_DtCvPointInfo **) _DtCvAddPtrToArray((void **) *ret_info,
1292 if (NULL == *ret_info)
1293 return _DtCvSTATUS_BAD;
1296 return _DtCvSTATUS_OK;
1299 /******************************************************************************
1301 ******************************************************************************/
1302 /*****************************************************************************
1303 * Function: _DtCanvasGetSelection()
1305 * Purpose: Indicate the end point for a selection.
1307 *****************************************************************************/
1309 _DtCanvasGetSelection (
1310 _DtCvHandle canvas_handle,
1312 _DtCvPointer *ret_select)
1314 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1317 return(GetSelectedText(canvas, canvas->select_start, canvas->select_end,
1321 /*****************************************************************************
1322 * Function: _DtCanvasProcessSelection()
1324 * Purpose: Indicate an new point for a selection.
1326 *****************************************************************************/
1328 _DtCanvasProcessSelection (
1329 _DtCvHandle canvas_handle,
1332 _DtCvSelectMode mode)
1334 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1335 _DtCvSelectData temp;
1339 case _DtCvSELECTION_CLEAR:
1340 CheckAndSwitchPoints(&(canvas->select_start),
1341 &(canvas->select_end));
1343 case _DtCvSELECTION_START:
1344 _DtCvDrawAreaWithFlags(canvas, canvas->select_start,
1346 _DtCvSELECTED_FLAG, 0,
1347 _DtCvBAD_TYPE, NULL);
1349 canvas->select_start = defaultSelect;
1350 if (mode == _DtCvSELECTION_START)
1351 SearchForClosestLine(canvas, x, y, &(canvas->select_start));
1353 canvas->select_end = canvas->select_start;
1356 case _DtCvSELECTION_END:
1357 case _DtCvSELECTION_UPDATE:
1358 SearchForClosestLine(canvas, x, y, &temp);
1360 AdjustSelection (canvas, temp);
1361 if (mode == _DtCvSELECTION_END)
1362 CheckAndSwitchPoints(&(canvas->select_start),
1363 &(canvas->select_end));
1368 /*****************************************************************************
1369 * Function: _DtCanvasGetSelectionPoints()
1371 * Purpose: Retrieve the segments making up the selection.
1373 *****************************************************************************/
1375 _DtCanvasGetSelectionPoints (
1376 _DtCvHandle canvas_handle,
1377 _DtCvSegPts ***ret_segs,
1381 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1383 return (GetSegsInArea(canvas, &(canvas->select_start),
1384 &(canvas->select_end), ret_segs, ret_y1, ret_y2));
1387 /*****************************************************************************
1388 * Function: _DtCanvasActivatePts()
1390 * Purpose: Activate the points given.
1392 *****************************************************************************/
1394 _DtCanvasActivatePts (
1395 _DtCvHandle canvas_handle,
1397 _DtCvPointInfo *info,
1402 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1403 _DtCvSelectData startSel = defaultSelect;
1404 _DtCvSelectData endSel = defaultSelect;
1406 _DtCvSegmentI *firstSeg;
1408 #define REQUIRE_SEGS \
1409 (_DtCvACTIVATE_MARK | _DtCvACTIVATE_SELECTION)
1411 * check to see if there is anything to do
1414 return _DtCvSTATUS_NONE;
1416 if ((mask & _DtCvACTIVATE_MARK) && (mask & _DtCvDEACTIVATE))
1417 return _DtCvSTATUS_BAD;
1420 * Convert the segments into starting and ending positions.
1422 if (((mask & _DtCvDEACTIVATE) && NULL == info->client_data)
1423 || (mask & REQUIRE_SEGS))
1425 if (NULL == info || NULL == info->segs ||
1426 _DtCvSTATUS_BAD == _DtCvCvtSegsToPts(canvas, info->segs,
1428 ret_y1, ret_y2, &firstSeg))
1429 return _DtCvSTATUS_BAD;
1433 * Activate as a selection
1435 if (mask & _DtCvACTIVATE_SELECTION)
1437 _DtCanvasProcessSelection (canvas_handle, 0, 0, _DtCvSELECTION_CLEAR);
1439 canvas->select_start = startSel;
1440 canvas->select_end = endSel;
1442 _DtCvDrawAreaWithFlags (canvas, startSel, endSel,
1443 0, _DtCvSELECTED_FLAG,
1444 _DtCvBAD_TYPE, NULL);
1448 * Activate as a mark
1450 if (mask & _DtCvACTIVATE_MARK)
1458 markIdx = _DtCvAddToMarkList(canvas, info->client_data,
1459 _DtCvIsMarkMaskOn(mask), &startSel, &endSel);
1461 return _DtCvSTATUS_BAD;
1464 * now put the mark in the traversal list and merge it into the
1467 travIdx = _DtCvGetNextTravEntry(canvas);
1469 || 0 != _DtCvSetTravEntryInfo(canvas, travIdx,
1470 _DtCvTraversalMark, firstSeg,
1472 || 0 != _DtCvCalcMarkPos(canvas, markIdx,
1473 &x, &y, &width, &height)
1474 || 0 != _DtCvSetTravEntryPos(canvas, travIdx,
1475 x, y, width, height))
1476 return _DtCvSTATUS_BAD;
1478 _DtCvSortTraversalList(canvas, _DtCvTRUE);
1481 * draw these segments marked.
1483 flag = _DtCvMARK_FLAG;
1484 if (_DtCvTRUE == canvas->marks[markIdx].on)
1485 flag |= _DtCvMARK_ON;
1487 _DtCvDrawAreaWithFlags (canvas, startSel, endSel,
1489 _DtCvBAD_TYPE, NULL);
1493 * Clear the mark flag.
1495 else if (mask & _DtCvDEACTIVATE)
1500 * is there anything to deacivate?
1502 if (NULL == canvas->marks || 0 == canvas->mark_cnt)
1503 return _DtCvSTATUS_BAD;
1506 * was client data specified? If so, then look for it and ignore
1510 if (NULL != info->client_data)
1512 while (markIdx < canvas->mark_cnt &&
1513 canvas->marks[markIdx].client_data != info->client_data)
1517 * initialize the selection points
1519 if (markIdx < canvas->mark_cnt)
1521 startSel = canvas->marks[markIdx].beg;
1522 endSel = canvas->marks[markIdx].end;
1526 * look for the marked set using the segments.
1530 while (markIdx < canvas->mark_cnt
1531 && startSel.line_idx != canvas->marks[markIdx].beg.line_idx
1532 && startSel.char_idx != canvas->marks[markIdx].beg.char_idx
1533 && endSel.line_idx != canvas->marks[markIdx].end.line_idx
1534 && endSel.line_idx != canvas->marks[markIdx].end.char_idx)
1538 if (markIdx >= canvas->mark_cnt)
1539 return _DtCvSTATUS_BAD;
1542 * draw these segments unmarked.
1544 flag = _DtCvMARK_FLAG;
1545 if (_DtCvTRUE == canvas->marks[markIdx].on)
1546 flag |= _DtCvMARK_ON;
1548 canvas->marks[markIdx].on = _DtCvFALSE;
1549 _DtCvDrawAreaWithFlags (canvas, startSel, endSel, flag, 0,
1550 _DtCvBAD_TYPE, NULL);
1553 * remove the mark from the traversal list
1555 * first find the traversal entry of the mark and adjust any
1556 * traversal mark index values to reflect that the mark
1557 * list is about to shrink by 1.
1559 for (travIdx = 0; _DtCvTraversalMark != canvas->trav_lst[travIdx].type
1560 || markIdx != canvas->trav_lst[travIdx].idx; travIdx++)
1563 * is this mark after the one being removed?
1564 * if so, decrease its index because it's about to move.
1566 if (_DtCvTraversalMark == canvas->trav_lst[travIdx].type &&
1567 markIdx < canvas->trav_lst[travIdx].idx)
1568 canvas->trav_lst[travIdx].idx--;
1572 * move the list of traversal entries to eliminate the mark entry.
1574 while (travIdx + 1 < canvas->trav_cnt)
1576 canvas->trav_lst[travIdx] = canvas->trav_lst[travIdx + 1];
1579 * is this a mark after the one being removed?
1580 * if so, decrease it's index because it's about to move.
1582 if (_DtCvTraversalMark == canvas->trav_lst[travIdx].type &&
1583 markIdx < canvas->trav_lst[travIdx].idx)
1584 canvas->trav_lst[travIdx].idx--;
1590 * update the traversal count and back up to the previous traversal
1591 * if the mark was at the end of the traversal list.
1594 if (canvas->cur_trav >= canvas->trav_cnt)
1598 * move the list of marks up
1600 while (markIdx + 1 < canvas->mark_cnt)
1602 canvas->marks[markIdx] = canvas->marks[markIdx + 1];
1608 else if ((_DtCvACTIVATE_MARK_ON | _DtCvACTIVATE_MARK_OFF) & mask)
1611 if (NULL != info && NULL != info->client_data)
1613 while (markIdx < canvas->mark_cnt &&
1614 canvas->marks[markIdx].client_data != info->client_data)
1618 * was a mark with this client data found?
1620 if (markIdx >= canvas->mark_cnt)
1621 return _DtCvSTATUS_BAD;
1626 * are there any traversals? Is the current one sitting on a mark?
1628 if (0 == canvas->trav_cnt || -1 == canvas->cur_trav ||
1629 _DtCvTraversalMark != canvas->trav_lst[canvas->cur_trav].type)
1630 return _DtCvSTATUS_BAD;
1633 * get the mark index
1635 markIdx = canvas->trav_lst[canvas->cur_trav].idx;
1639 * is this different than what it is set at now? If not, do nothing.
1641 if (_DtCvIsMarkMaskOn(mask) == canvas->marks[markIdx].on)
1642 return _DtCvSTATUS_NONE;
1645 * set to mask value.
1647 canvas->marks[markIdx].on = _DtCvIsMarkMaskOn(mask);
1650 * set the flags correctly.
1652 flag = _DtCvMARK_FLAG;
1653 if (_DtCvTRUE == canvas->marks[markIdx].on)
1654 flag |= _DtCvMARK_ON;
1655 if (_DtCvTRUE == canvas->trav_on &&
1656 markIdx == canvas->trav_lst[canvas->cur_trav].idx)
1657 flag |= _DtCvTRAVERSAL_FLAG;
1660 * draw the mark opposite what it was
1662 _DtCvDrawAreaWithFlags (canvas, canvas->marks[markIdx].beg,
1663 canvas->marks[markIdx].end,
1664 (flag ^ _DtCvMARK_ON), flag,
1665 _DtCvBAD_TYPE, NULL);
1668 return _DtCvSTATUS_OK;
1671 /*****************************************************************************
1672 * Function: _DtCanvasGetMarkPositions()
1674 * Purpose: Return the position in the canvas of the marks.
1676 *****************************************************************************/
1678 _DtCanvasGetMarkPositions (
1679 _DtCvHandle canvas_handle,
1680 _DtCvMarkPos ***ret_pos)
1683 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1684 _DtCvMarkPos *nextPos;
1685 _DtCvMarkData *markLst = canvas->marks;
1689 if (0 == canvas->mark_cnt)
1690 return _DtCvSTATUS_NONE;
1692 for (i = 0; i < canvas->mark_cnt; i++, markLst++)
1695 * malloc memory for the information
1697 nextPos = (_DtCvMarkPos *) malloc (sizeof(_DtCvMarkPos));
1698 if (NULL == nextPos)
1699 return _DtCvSTATUS_BAD;
1702 * client data and baselines
1704 nextPos->client_data = markLst->client_data;
1705 nextPos->baseline1 = canvas->txt_lst[markLst->beg.line_idx].baseline;
1706 nextPos->baseline2 = canvas->txt_lst[markLst->end.line_idx].baseline;
1711 nextPos->x1 = markLst->beg.x;
1712 nextPos->y1 = nextPos->baseline1 -
1713 canvas->txt_lst[markLst->beg.line_idx].ascent;
1716 * bottom right corner
1718 nextPos->x2 = markLst->end.x;
1719 nextPos->y2 = nextPos->baseline2 +
1720 canvas->txt_lst[markLst->end.line_idx].descent;
1722 *ret_pos = (_DtCvMarkPos **) _DtCvAddPtrToArray((void **) *ret_pos,
1724 if (NULL == *ret_pos)
1725 return _DtCvSTATUS_BAD;
1728 return _DtCvSTATUS_OK;