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)
574 _DtCvDspLine *lines = canvas->txt_lst;
575 _DtCvStringInfo strInfo = { NULL, 0, 1, NULL };
577 topY = lines[line_idx].baseline - lines[line_idx].ascent;
578 if (topY > prev_y && canvas->virt_functions.build_selection != NULL)
581 _DtCvUnit lineSize = canvas->metrics.line_height / 2;
585 newLines = (topY - prev_y) / lineSize;
589 if ((*(canvas->virt_functions.build_selection))(
590 canvas->client_data, _DtCvSTRING_TYPE,
591 mask, ret_data, 0, 0, _DtCvEND_OF_LINE,
592 (_DtCvPointer) &strInfo) != _DtCvSTATUS_OK)
598 *ret_x = AddSegmentToData (canvas, mask, target_x, line_idx, char_idx,
599 copy_cnt, end_flag, ret_y, ret_data);
600 _DtCvSetProcessed(lines[line_idx]);
607 /*****************************************************************************
610 *****************************************************************************/
620 _DtCvUnit curMin = -1;
623 for (i = 0; i < txt_cnt; i++)
625 if (_DtCvIsNotProcessed(lines[i]))
627 if (lines[i].baseline - lines[i].ascent < target_y &&
628 target_y <= lines[i].baseline + lines[i].descent)
631 curX = lines[i].text_x;
633 if (curMin == -1 || curMin > curX)
644 /*****************************************************************************
645 * Function: FindNextMinY
647 *****************************************************************************/
657 _DtCvValue found = False;
661 if (_DtCvIsNotProcessed(lines[i]))
663 maxY = lines[i].baseline + lines[i].descent;
664 if (target_y == -1 || maxY < target_y)
669 SkipOtherLines (lines, max_cnt, i+1, target_y, &i);
679 /*****************************************************************************
680 * Function: GetSelectedText
682 *****************************************************************************/
685 _DtCanvasStruct *canvas,
686 _DtCvSelectData next,
689 _DtCvPointer *ret_data)
698 int txtCnt = canvas->txt_cnt;
700 _DtCvValue processing = True;
701 _DtCvDspLine *lines = canvas->txt_lst;
703 for (i = 0; i < txtCnt; i++)
704 _DtCvClearProcessed(lines[i]);
706 MarkLinesOutsideBoundary(canvas, next.y, next.x, end.y, end.x);
709 if (next.line_idx == -1)
712 * find the first selected line
714 if (FindNextMinY(lines, txtCnt, -1, &next.y) == False)
718 lineCnt = FindMinX(lines, txtCnt, next.y, &next.line_idx);
722 lineCnt = FindMinX(lines, txtCnt, next.y, &junk);
724 while (processing == True && result == 0)
727 * process the next line of text.
732 cpyCnt = lines[next.line_idx].length - next.char_idx;
733 if (next.line_idx == end.line_idx)
734 cpyCnt = cpyCnt - lines[next.line_idx].length + end.char_idx;
735 else if (lineCnt == 1)
736 endFlag = _DtCvEND_OF_LINE;
738 result = BuildLine(canvas, mask, maxY, next.x,
739 next.line_idx, next.char_idx,
741 &next.x, &botY, ret_data);
747 lineCnt = FindMinX(lines, txtCnt, next.y, &next.line_idx);
749 } while (result == 0 && lineCnt > 0);
754 processing = FindNextMinY(lines, txtCnt, -1, &next.y);
755 if (processing == True)
756 lineCnt = FindMinX(lines, txtCnt, next.y, &next.line_idx);
762 } /* End GetSelectedText */
764 /*****************************************************************************
765 * Function: GetSegsInArea()
767 * Purpose: Retrieve the segments making up the selection.
769 *****************************************************************************/
772 _DtCanvasStruct *canvas,
773 _DtCvSelectData *beg,
774 _DtCvSelectData *end,
775 _DtCvSegPts ***ret_segs,
785 _DtCvValue processing = True;
789 _DtCvSelectData next;
792 _DtCvDspLine *lines = canvas->txt_lst;
797 return _DtCvSTATUS_NONE;
800 * make sure the selection points are in the correct order.
802 CheckAndSwitchPoints(beg, end);
805 * clear the processed bit
807 for (cnt = 0; cnt < canvas->txt_cnt; cnt++)
808 _DtCvClearProcessed(lines[cnt]);
811 * initialize the working structure
812 * mark all the lines outside the selection regiion as invalid
815 MarkLinesOutsideBoundary(canvas, next.y, next.x, end->y, end->x);
818 * start the minimum and maximum Y at this location.
824 * is there a line at this location?
826 if (next.line_idx == -1)
829 * find the first selected line within the region.
831 if (FindNextMinY(lines, canvas->txt_cnt, -1, &next.y) == False)
832 processing = False; /* empty of any text */
836 * now find the first line that is on this 'line' and
837 * the number of lines.
840 lineCnt = FindMinX(lines, canvas->txt_cnt, next.y, &next.line_idx);
844 else /* find the number of lines on this 'line' */
845 lineCnt = FindMinX(lines, canvas->txt_cnt, next.y, &cnt);
848 * loop will there are segments to process
850 while (processing == True && result == 0)
853 * process the next line of text.
855 while (result == 0 && lineCnt > 0)
858 * for each segment in this line (that is selected)
859 * create a segment point for it.
861 length = lines[next.line_idx].length;
862 start = lines[next.line_idx].byte_index;
865 * if this is the last line, shorten the length
866 * by the ending index.
868 if (next.line_idx == end->line_idx)
869 length = end->char_idx;
872 * move through the line's segments until we
873 * hit the segment starting the selection
875 pSeg = lines[next.line_idx].seg_ptr;
876 count = next.char_idx;
877 while (NULL != pSeg && 0 < count)
880 * get the byte count of this segment
882 _DtCvGetWidthOfSegment(canvas, pSeg, start, length,
886 * is the byte count of this segment larger than
887 * the starting index of the selection? If not,
888 * the selection is after this segment.
894 pSeg = pSeg->next_disp;
899 start = start + count;
904 while (0 == result && NULL != pSeg && 0 < length)
907 * start with error condition. If the malloc works
908 * the error result gets reset to valid.
911 newPt = (_DtCvSegPts *) malloc (sizeof(_DtCvSegPts));
915 * indicate everything is okay.
920 * get the width of this segment
922 _DtCvGetWidthOfSegment(canvas, pSeg, start, length,
926 * now set the segment point information and add it to the
927 * array of segment points.
929 newPt->offset = start;
931 newPt->segment = pSeg;
933 *ret_segs = (_DtCvSegPts **) _DtCvAddPtrToArray(
936 if (NULL == *ret_segs)
939 pSeg = pSeg->next_disp;
946 * does this line extend below the selection y?
947 * if so, report it as the maximum y.
949 botY = lines[next.line_idx].baseline + lines[next.line_idx].descent;
954 * indicate this line has been processed.
956 _DtCvSetProcessed(lines[next.line_idx]);
962 lineCnt = FindMinX(lines, canvas->txt_cnt, next.y,
969 processing = FindNextMinY(lines,canvas->txt_cnt, -1, &next.y);
970 if (processing == True)
971 lineCnt = FindMinX(lines,canvas->txt_cnt,next.y,&next.line_idx);
976 * if no errors, add a null to the array
980 *ret_segs = (_DtCvSegPts **) _DtCvAddPtrToArray((void **) *ret_segs,
982 if (NULL == *ret_segs)
987 * if errors, free the segment points and return a bad status.
991 if (NULL != *ret_segs)
993 for (lineCnt = 0; NULL != (*ret_segs)[lineCnt]; lineCnt++)
994 free((*ret_segs)[lineCnt]);
997 return _DtCvSTATUS_BAD;
1006 return _DtCvSTATUS_OK;
1009 /******************************************************************************
1010 * Semi-Public Functions
1011 ******************************************************************************/
1012 /*****************************************************************************
1013 * Function: _DtCvDrawAreaWithFlags
1015 *****************************************************************************/
1017 _DtCvDrawAreaWithFlags (
1018 _DtCanvasStruct *canvas,
1019 _DtCvSelectData start,
1020 _DtCvSelectData end,
1021 _DtCvFlags old_flags,
1022 _DtCvFlags new_flags,
1023 _DtCvElemType trav_type,
1024 _DtCvPointer trav_data)
1034 _DtCvUnit superWidth;
1040 _DtCvSegmentI *pSeg;
1041 _DtCvValue lstLinkVis;
1042 _DtCvValue lstWasSuper;
1043 _DtCvValue lstWasSub;
1045 _DtCvFlags flagMask = old_flags | new_flags;
1046 _DtCvFlags endFlag = flagMask & _DtCvTRAVERSAL_END;
1048 _DtCvDspLine *lines = canvas->txt_lst;
1051 * now use the flagMask to determine what else to look for.
1052 * I.e. if flagMask has _DtCvMARK_FLAG set, then it becomes
1053 * set to _DtCvSELECTED_FLAG and visa versa.
1055 flagMask ^= (_DtCvSELECTED_FLAG | _DtCvMARK_FLAG);
1058 * strip the end flag from the other flags
1060 new_flags &= ~(_DtCvTRAVERSAL_END);
1061 old_flags &= ~(_DtCvTRAVERSAL_END);
1063 if (Equal(start, end))
1066 for (i = 0; i < canvas->txt_cnt; i++)
1068 topY = lines[i].baseline - lines[i].ascent;
1069 botY = lines[i].baseline + lines[i].descent;
1071 if (InRegion(topY, botY, start.y, end.y))
1074 * get the start of the text.
1077 lstWasSuper = False;
1080 dstX = _DtCvGetStartXOfLine(&(lines[i]), &pSeg);
1081 startChar = lines[i].byte_index;
1082 count = lines[i].length;
1084 while (pSeg != NULL && _DtCvIsSegNoop(pSeg))
1087 pSeg = pSeg->next_disp;
1091 * advance the starting point
1093 dstX = _DtCvAdvanceXOfLine(canvas, pSeg, dstX,
1094 &lnkInd, &lstLinkVis);
1096 * take into account super/sub scripting
1098 dstX = _DtCvAdjustForSuperSub(canvas, pSeg, dstX, &scriptX,
1099 &superWidth, &superY, &subWidth, &subY,
1100 &lstWasSuper, &lstWasSub);
1103 * set this flag so that the first pass of 'while (cnt > 0)'
1104 * doesn't do it again.
1108 if (_DtCvStraddlesPt(start.y, topY, botY))
1112 * I.E. is this line before the start or after the end?
1114 if (canvas->txt_lst[i].max_x < start.x ||
1115 end.y == start.y && end.x <= dstX )
1119 * does this line start the mark/selection?
1121 if (i == start.line_idx && start.x >= dstX)
1123 int cnt = start.char_idx;
1127 if (trimmed == False)
1130 * advance the starting point
1132 dstX = _DtCvAdvanceXOfLine(canvas, pSeg, dstX,
1133 &lnkInd, &lstLinkVis);
1135 * take into account super/sub scripting
1137 dstX = _DtCvAdjustForSuperSub(canvas,
1138 pSeg, dstX, &scriptX,
1139 &superWidth, &superY, &subWidth, &subY,
1140 &lstWasSuper, &lstWasSub);
1144 * take into account the length of the segment
1146 _DtCvGetWidthOfSegment(canvas, pSeg,
1148 &len, &segWidth, &trimmed);
1152 if (trimmed == False)
1155 pSeg = pSeg->next_disp;
1164 count -= start.char_idx;
1168 * otherwise this line is after the line that starts
1169 * the mark/selection. Stick with its start x.
1174 * does this straddle the end point?
1176 if (_DtCvStraddlesPt(end.y, topY, botY))
1179 * does this start after the end of the mark/selection?
1186 * Does this segment end after the end of the mark/selection?
1187 * If so, trim how much gets highlighted.
1189 if (canvas->txt_lst[i].max_x > end.x)
1190 count -= (lines[i].length - end.char_idx);
1194 * while there is something to draw (un)mark/selected.
1196 old_flags = old_flags | _DtCvMARK_BEGIN;
1197 new_flags = new_flags | _DtCvMARK_BEGIN;
1201 * the original count to render
1206 * check for other marks and selection.
1208 _DtCvCheckLineMarks(canvas, i, startChar - lines[i].byte_index,
1209 count, dstX, flagMask,
1210 &len, &old_flags, &new_flags);
1213 * if this is the last segment(s) of the (un)mark/selection
1214 * set the end flags.
1218 new_flags |= (endFlag | _DtCvLINK_END | _DtCvMARK_END);
1219 old_flags |= (endFlag | _DtCvLINK_END | _DtCvMARK_END);
1223 * draw the segments that are marked/unmarked.
1225 dstX = _DtCvDrawSegments(canvas, lines[i],
1226 pSeg, startChar , len, &lnkInd,
1227 dstX, dstX, &scriptX,
1228 &superWidth, &superY, &subWidth, &subY,
1229 &lstWasSub, &lstWasSuper,
1230 &lstLinkVis, old_flags, new_flags,
1231 trav_type, trav_data);
1233 * modify the count by the length processed
1238 * did this do the entire length? If not, set the
1239 * indexes ahead and do again.
1242 _DtCvSkipLineChars(canvas, pSeg, startChar , count + len,
1243 len, &startChar , &pSeg);
1246 * strip the any begin flags.
1248 _DtCvRemoveBeginFlags(old_flags);
1249 _DtCvRemoveBeginFlags(new_flags);
1255 /*****************************************************************************
1256 * Function: _DtCanvasGetSelectionPoints()
1258 * Purpose: Retrieve the segments making up the selection.
1260 *****************************************************************************/
1263 _DtCanvasStruct *canvas,
1264 _DtCvPointInfo ***ret_info)
1270 for (i = 0; i < canvas->mark_cnt; i++)
1272 _DtCvPointInfo *nxtInfo;
1275 * allocate mark information structure
1277 nxtInfo = (_DtCvPointInfo *) malloc (sizeof(_DtCvPointInfo));
1278 if (NULL == nxtInfo)
1279 return _DtCvSTATUS_BAD;
1281 nxtInfo->client_data = canvas->marks[i].client_data;
1283 if (_DtCvSTATUS_BAD == GetSegsInArea(canvas, &(canvas->marks[i].beg),
1284 &(canvas->marks[i].end),
1287 return _DtCvSTATUS_BAD;
1289 *ret_info = (_DtCvPointInfo **) _DtCvAddPtrToArray((void **) *ret_info,
1291 if (NULL == *ret_info)
1292 return _DtCvSTATUS_BAD;
1295 return _DtCvSTATUS_OK;
1298 /******************************************************************************
1300 ******************************************************************************/
1301 /*****************************************************************************
1302 * Function: _DtCanvasGetSelection()
1304 * Purpose: Indicate the end point for a selection.
1306 *****************************************************************************/
1308 _DtCanvasGetSelection (
1309 _DtCvHandle canvas_handle,
1311 _DtCvPointer *ret_select)
1313 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1316 return(GetSelectedText(canvas, canvas->select_start, canvas->select_end,
1320 /*****************************************************************************
1321 * Function: _DtCanvasProcessSelection()
1323 * Purpose: Indicate an new point for a selection.
1325 *****************************************************************************/
1327 _DtCanvasProcessSelection (
1328 _DtCvHandle canvas_handle,
1331 _DtCvSelectMode mode)
1333 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1334 _DtCvSelectData temp;
1338 case _DtCvSELECTION_CLEAR:
1339 CheckAndSwitchPoints(&(canvas->select_start),
1340 &(canvas->select_end));
1342 case _DtCvSELECTION_START:
1343 _DtCvDrawAreaWithFlags(canvas, canvas->select_start,
1345 _DtCvSELECTED_FLAG, 0,
1346 _DtCvBAD_TYPE, NULL);
1348 canvas->select_start = defaultSelect;
1349 if (mode == _DtCvSELECTION_START)
1350 SearchForClosestLine(canvas, x, y, &(canvas->select_start));
1352 canvas->select_end = canvas->select_start;
1355 case _DtCvSELECTION_END:
1356 case _DtCvSELECTION_UPDATE:
1357 SearchForClosestLine(canvas, x, y, &temp);
1359 AdjustSelection (canvas, temp);
1360 if (mode == _DtCvSELECTION_END)
1361 CheckAndSwitchPoints(&(canvas->select_start),
1362 &(canvas->select_end));
1367 /*****************************************************************************
1368 * Function: _DtCanvasGetSelectionPoints()
1370 * Purpose: Retrieve the segments making up the selection.
1372 *****************************************************************************/
1374 _DtCanvasGetSelectionPoints (
1375 _DtCvHandle canvas_handle,
1376 _DtCvSegPts ***ret_segs,
1380 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1382 return (GetSegsInArea(canvas, &(canvas->select_start),
1383 &(canvas->select_end), ret_segs, ret_y1, ret_y2));
1386 /*****************************************************************************
1387 * Function: _DtCanvasActivatePts()
1389 * Purpose: Activate the points given.
1391 *****************************************************************************/
1393 _DtCanvasActivatePts (
1394 _DtCvHandle canvas_handle,
1396 _DtCvPointInfo *info,
1401 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1402 _DtCvSelectData startSel = defaultSelect;
1403 _DtCvSelectData endSel = defaultSelect;
1405 _DtCvSegmentI *firstSeg;
1407 #define REQUIRE_SEGS \
1408 (_DtCvACTIVATE_MARK | _DtCvACTIVATE_SELECTION)
1410 * check to see if there is anything to do
1413 return _DtCvSTATUS_NONE;
1415 if ((mask & _DtCvACTIVATE_MARK) && (mask & _DtCvDEACTIVATE))
1416 return _DtCvSTATUS_BAD;
1419 * Convert the segments into starting and ending positions.
1421 if (((mask & _DtCvDEACTIVATE) && NULL == info->client_data)
1422 || (mask & REQUIRE_SEGS))
1424 if (NULL == info || NULL == info->segs ||
1425 _DtCvSTATUS_BAD == _DtCvCvtSegsToPts(canvas, info->segs,
1427 ret_y1, ret_y2, &firstSeg))
1428 return _DtCvSTATUS_BAD;
1432 * Activate as a selection
1434 if (mask & _DtCvACTIVATE_SELECTION)
1436 _DtCanvasProcessSelection (canvas_handle, 0, 0, _DtCvSELECTION_CLEAR);
1438 canvas->select_start = startSel;
1439 canvas->select_end = endSel;
1441 _DtCvDrawAreaWithFlags (canvas, startSel, endSel,
1442 0, _DtCvSELECTED_FLAG,
1443 _DtCvBAD_TYPE, NULL);
1447 * Activate as a mark
1449 if (mask & _DtCvACTIVATE_MARK)
1457 markIdx = _DtCvAddToMarkList(canvas, info->client_data,
1458 _DtCvIsMarkMaskOn(mask), &startSel, &endSel);
1460 return _DtCvSTATUS_BAD;
1463 * now put the mark in the traversal list and merge it into the
1466 travIdx = _DtCvGetNextTravEntry(canvas);
1468 || 0 != _DtCvSetTravEntryInfo(canvas, travIdx,
1469 _DtCvTraversalMark, firstSeg,
1471 || 0 != _DtCvCalcMarkPos(canvas, markIdx,
1472 &x, &y, &width, &height)
1473 || 0 != _DtCvSetTravEntryPos(canvas, travIdx,
1474 x, y, width, height))
1475 return _DtCvSTATUS_BAD;
1477 _DtCvSortTraversalList(canvas, _DtCvTRUE);
1480 * draw these segments marked.
1482 flag = _DtCvMARK_FLAG;
1483 if (_DtCvTRUE == canvas->marks[markIdx].on)
1484 flag |= _DtCvMARK_ON;
1486 _DtCvDrawAreaWithFlags (canvas, startSel, endSel,
1488 _DtCvBAD_TYPE, NULL);
1492 * Clear the mark flag.
1494 else if (mask & _DtCvDEACTIVATE)
1499 * is there anything to deacivate?
1501 if (NULL == canvas->marks || 0 == canvas->mark_cnt)
1502 return _DtCvSTATUS_BAD;
1505 * was client data specified? If so, then look for it and ignore
1509 if (NULL != info->client_data)
1511 while (markIdx < canvas->mark_cnt &&
1512 canvas->marks[markIdx].client_data != info->client_data)
1516 * initialize the selection points
1518 if (markIdx < canvas->mark_cnt)
1520 startSel = canvas->marks[markIdx].beg;
1521 endSel = canvas->marks[markIdx].end;
1525 * look for the marked set using the segments.
1529 while (markIdx < canvas->mark_cnt
1530 && startSel.line_idx != canvas->marks[markIdx].beg.line_idx
1531 && startSel.char_idx != canvas->marks[markIdx].beg.char_idx
1532 && endSel.line_idx != canvas->marks[markIdx].end.line_idx
1533 && endSel.line_idx != canvas->marks[markIdx].end.char_idx)
1537 if (markIdx >= canvas->mark_cnt)
1538 return _DtCvSTATUS_BAD;
1541 * draw these segments unmarked.
1543 flag = _DtCvMARK_FLAG;
1544 if (_DtCvTRUE == canvas->marks[markIdx].on)
1545 flag |= _DtCvMARK_ON;
1547 canvas->marks[markIdx].on = _DtCvFALSE;
1548 _DtCvDrawAreaWithFlags (canvas, startSel, endSel, flag, 0,
1549 _DtCvBAD_TYPE, NULL);
1552 * remove the mark from the traversal list
1554 * first find the traversal entry of the mark and adjust any
1555 * traversal mark index values to reflect that the mark
1556 * list is about to shrink by 1.
1558 for (travIdx = 0; _DtCvTraversalMark != canvas->trav_lst[travIdx].type
1559 || markIdx != canvas->trav_lst[travIdx].idx; travIdx++)
1562 * is this mark after the one being removed?
1563 * if so, decrease its index because it's about to move.
1565 if (_DtCvTraversalMark == canvas->trav_lst[travIdx].type &&
1566 markIdx < canvas->trav_lst[travIdx].idx)
1567 canvas->trav_lst[travIdx].idx--;
1571 * move the list of traversal entries to eliminate the mark entry.
1573 while (travIdx + 1 < canvas->trav_cnt)
1575 canvas->trav_lst[travIdx] = canvas->trav_lst[travIdx + 1];
1578 * is this a mark after the one being removed?
1579 * if so, decrease it's index because it's about to move.
1581 if (_DtCvTraversalMark == canvas->trav_lst[travIdx].type &&
1582 markIdx < canvas->trav_lst[travIdx].idx)
1583 canvas->trav_lst[travIdx].idx--;
1589 * update the traversal count and back up to the previous traversal
1590 * if the mark was at the end of the traversal list.
1593 if (canvas->cur_trav >= canvas->trav_cnt)
1597 * move the list of marks up
1599 while (markIdx + 1 < canvas->mark_cnt)
1601 canvas->marks[markIdx] = canvas->marks[markIdx + 1];
1607 else if ((_DtCvACTIVATE_MARK_ON | _DtCvACTIVATE_MARK_OFF) & mask)
1610 if (NULL != info && NULL != info->client_data)
1612 while (markIdx < canvas->mark_cnt &&
1613 canvas->marks[markIdx].client_data != info->client_data)
1617 * was a mark with this client data found?
1619 if (markIdx >= canvas->mark_cnt)
1620 return _DtCvSTATUS_BAD;
1625 * are there any traversals? Is the current one sitting on a mark?
1627 if (0 == canvas->trav_cnt || -1 == canvas->cur_trav ||
1628 _DtCvTraversalMark != canvas->trav_lst[canvas->cur_trav].type)
1629 return _DtCvSTATUS_BAD;
1632 * get the mark index
1634 markIdx = canvas->trav_lst[canvas->cur_trav].idx;
1638 * is this different than what it is set at now? If not, do nothing.
1640 if (_DtCvIsMarkMaskOn(mask) == canvas->marks[markIdx].on)
1641 return _DtCvSTATUS_NONE;
1644 * set to mask value.
1646 canvas->marks[markIdx].on = _DtCvIsMarkMaskOn(mask);
1649 * set the flags correctly.
1651 flag = _DtCvMARK_FLAG;
1652 if (_DtCvTRUE == canvas->marks[markIdx].on)
1653 flag |= _DtCvMARK_ON;
1654 if (_DtCvTRUE == canvas->trav_on &&
1655 markIdx == canvas->trav_lst[canvas->cur_trav].idx)
1656 flag |= _DtCvTRAVERSAL_FLAG;
1659 * draw the mark opposite what it was
1661 _DtCvDrawAreaWithFlags (canvas, canvas->marks[markIdx].beg,
1662 canvas->marks[markIdx].end,
1663 (flag ^ _DtCvMARK_ON), flag,
1664 _DtCvBAD_TYPE, NULL);
1667 return _DtCvSTATUS_OK;
1670 /*****************************************************************************
1671 * Function: _DtCanvasGetMarkPositions()
1673 * Purpose: Return the position in the canvas of the marks.
1675 *****************************************************************************/
1677 _DtCanvasGetMarkPositions (
1678 _DtCvHandle canvas_handle,
1679 _DtCvMarkPos ***ret_pos)
1682 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
1683 _DtCvMarkPos *nextPos;
1684 _DtCvMarkData *markLst = canvas->marks;
1688 if (0 == canvas->mark_cnt)
1689 return _DtCvSTATUS_NONE;
1691 for (i = 0; i < canvas->mark_cnt; i++, markLst++)
1694 * malloc memory for the information
1696 nextPos = (_DtCvMarkPos *) malloc (sizeof(_DtCvMarkPos));
1697 if (NULL == nextPos)
1698 return _DtCvSTATUS_BAD;
1701 * client data and baselines
1703 nextPos->client_data = markLst->client_data;
1704 nextPos->baseline1 = canvas->txt_lst[markLst->beg.line_idx].baseline;
1705 nextPos->baseline2 = canvas->txt_lst[markLst->end.line_idx].baseline;
1710 nextPos->x1 = markLst->beg.x;
1711 nextPos->y1 = nextPos->baseline1 -
1712 canvas->txt_lst[markLst->beg.line_idx].ascent;
1715 * bottom right corner
1717 nextPos->x2 = markLst->end.x;
1718 nextPos->y2 = nextPos->baseline2 +
1719 canvas->txt_lst[markLst->end.line_idx].descent;
1721 *ret_pos = (_DtCvMarkPos **) _DtCvAddPtrToArray((void **) *ret_pos,
1723 if (NULL == *ret_pos)
1724 return _DtCvSTATUS_BAD;
1727 return _DtCvSTATUS_OK;