ReactOS 0.4.16-dev-1279-gc894716
caret.c
Go to the documentation of this file.
1/*
2 * RichEdit - Caret and selection functions.
3 *
4 * Copyright 2004 by Krzysztof Foltman
5 * Copyright 2005 by Phil Krylov
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22
23#include "editor.h"
24
26
28{
29 cursor->para = editor_first_para( editor );
30 cursor->run = para_first_run( cursor->para );
31 cursor->nOffset = 0;
32}
33
34static void ME_SetCursorToEnd(ME_TextEditor *editor, ME_Cursor *cursor, BOOL final_eop)
35{
36 cursor->para = para_prev( editor_end_para( editor ) );
37 cursor->run = para_end_run( cursor->para );
38 cursor->nOffset = final_eop ? cursor->run->len : 0;
39}
40
41
43{
44 *from = ME_GetCursorOfs(&editor->pCursors[0]);
45 *to = ME_GetCursorOfs(&editor->pCursors[1]);
46
47 if (*from > *to)
48 {
49 LONG tmp = *from;
50 *from = *to;
51 *to = tmp;
52 return 1;
53 }
54 return 0;
55}
56
58{
59 int from_ofs = ME_GetCursorOfs( &editor->pCursors[0] );
60 int to_ofs = ME_GetCursorOfs( &editor->pCursors[1] );
61 BOOL swap = (from_ofs > to_ofs);
62
63 if (from_ofs == to_ofs)
64 {
65 /* If cursor[0] is at the beginning of a run and cursor[1] at the end
66 of the prev run then we need to swap. */
67 if (editor->pCursors[0].nOffset < editor->pCursors[1].nOffset)
68 swap = TRUE;
69 }
70
71 if (!swap)
72 {
73 *from = &editor->pCursors[0];
74 *to = &editor->pCursors[1];
75 return 0;
76 } else {
77 *from = &editor->pCursors[1];
78 *to = &editor->pCursors[0];
79 return 1;
80 }
81}
82
84{
87 return ME_GetCursorOfs(&cursor);
88}
89
90
92{
93 int length;
94
95 if (how->flags & GTL_PRECISE && how->flags & GTL_CLOSE)
96 return E_INVALIDARG;
97 if (how->flags & GTL_NUMCHARS && how->flags & GTL_NUMBYTES)
98 return E_INVALIDARG;
99
100 length = ME_GetTextLength(editor);
101
102 if ((editor->props & TXTBIT_MULTILINE)
103 && (how->flags & GTL_USECRLF)
104 && !editor->bEmulateVersion10) /* Ignore GTL_USECRLF flag in 1.0 emulation */
105 length += editor->nParagraphs - 1;
106
107 if (how->flags & GTL_NUMBYTES ||
108 (how->flags & GTL_PRECISE && /* GTL_PRECISE seems to imply GTL_NUMBYTES */
109 !(how->flags & GTL_NUMCHARS))) /* unless GTL_NUMCHARS is given */
110 {
111 CPINFO cpinfo;
112
113 if (how->codepage == 1200)
114 return length * 2;
115 if (how->flags & GTL_PRECISE)
116 FIXME("GTL_PRECISE flag unsupported. Using GTL_CLOSE\n");
117 if (GetCPInfo(how->codepage, &cpinfo))
118 return length * cpinfo.MaxCharSize;
119 ERR("Invalid codepage %u\n", how->codepage);
120 return E_INVALIDARG;
121 }
122 return length;
123}
124
125/******************************************************************
126 * set_selection_cursors
127 *
128 * Updates the selection cursors.
129 *
130 * Note that this does not invalidate either the old or the new selections.
131 */
132int set_selection_cursors(ME_TextEditor *editor, int from, int to)
133{
134 int selectionEnd = 0;
135 const int len = ME_GetTextLength(editor);
136
137 /* all negative values are effectively the same */
138 if (from < 0)
139 from = -1;
140 if (to < 0)
141 to = -1;
142
143 /* select all */
144 if (from == 0 && to == -1)
145 {
146 ME_SetCursorToStart(editor, &editor->pCursors[1]);
147 ME_SetCursorToEnd(editor, &editor->pCursors[0], TRUE);
148 return len + 1;
149 }
150
151 /* if both values are equal and also out of bound, that means to */
152 /* put the selection at the end of the text */
153 if ((from == to) && (to < 0 || to > len))
154 {
155 selectionEnd = 1;
156 }
157 else
158 {
159 /* if from is negative and to is positive then selection is */
160 /* deselected and caret moved to end of the current selection */
161 if (from < 0)
162 {
163 LONG start, end;
164 ME_GetSelectionOfs(editor, &start, &end);
165 if (start != end)
166 {
167 if (end > len)
168 {
169 editor->pCursors[0].nOffset = 0;
170 end --;
171 }
172 editor->pCursors[1] = editor->pCursors[0];
173 }
174 return end;
175 }
176
177 /* adjust to if it's a negative value */
178 if (to < 0)
179 to = len + 1;
180
181 /* flip from and to if they are reversed */
182 if (from>to)
183 {
184 int tmp = from;
185 from = to;
186 to = tmp;
187 }
188
189 /* after fiddling with the values, we find from > len && to > len */
190 if (from > len)
191 selectionEnd = 1;
192 /* special case with to too big */
193 else if (to > len)
194 to = len + 1;
195 }
196
197 if (selectionEnd)
198 {
199 ME_SetCursorToEnd(editor, &editor->pCursors[0], FALSE);
200 editor->pCursors[1] = editor->pCursors[0];
201 return len;
202 }
203
204 cursor_from_char_ofs( editor, from, &editor->pCursors[1] );
205 editor->pCursors[0] = editor->pCursors[1];
206 ME_MoveCursorChars(editor, &editor->pCursors[0], to - from, FALSE);
207 /* Selection is not allowed in the middle of an end paragraph run. */
208 if (editor->pCursors[1].run->nFlags & MERF_ENDPARA)
209 editor->pCursors[1].nOffset = 0;
210 if (editor->pCursors[0].run->nFlags & MERF_ENDPARA)
211 {
212 if (to > len)
213 editor->pCursors[0].nOffset = editor->pCursors[0].run->len;
214 else
215 editor->pCursors[0].nOffset = 0;
216 }
217 return to;
218}
219
220
222 int *x, int *y, int *height )
223{
224 ME_Row *row;
225 ME_Run *run = cursor->run;
226 ME_Paragraph *para = cursor->para;
227 ME_Run *size_run = run, *prev;
229 int run_x;
230 HDC hdc = ITextHost_TxGetDC( editor->texthost );
231
232 assert(~para->nFlags & MEPF_REWRAP);
233
235
236 ME_InitContext( &c, editor, hdc );
237
238 if (!cursor->nOffset && (prev = run_prev( run ))) size_run = prev;
239
240 run_x = ME_PointFromCharContext( &c, run, cursor->nOffset, TRUE );
241
242 *height = size_run->nAscent + size_run->nDescent;
243 *x = c.rcView.left + run->pt.x + run_x - editor->horz_si.nPos;
244 *y = c.rcView.top + para->pt.y + row->nBaseline
245 + run->pt.y - size_run->nAscent - editor->vert_si.nPos;
248 return;
249}
250
252{
253 int x, y, height;
254
255 cursor_coords( editor, &editor->pCursors[0], &x, &y, &height );
257 editor->caret_height = height;
258 editor->caret_hidden = TRUE;
259}
260
262{
264 editor->caret_hidden = FALSE;
265}
266
268{
269 /* calls to HideCaret are cumulative; do so only once */
270 if (!editor->caret_hidden)
271 {
273 editor->caret_hidden = TRUE;
274 }
275}
276
278{
279 int x, y, height;
280
281 if (!editor->bHaveFocus) return;
282 if (!ME_IsSelection(editor))
283 {
284 cursor_coords( editor, &editor->pCursors[0], &x, &y, &height );
285 if (height != editor->caret_height) create_caret(editor);
286 x = min(x, editor->rcFormat.right-1);
288 show_caret(editor);
289 }
290 else
291 hide_caret(editor);
292#ifdef __REACTOS__
294 {
295 HIMC hIMC = ImmGetContext(editor->hWnd);
296 if (hIMC)
297 {
299 LOGFONTW lf;
300 COMPOSITIONFORM CompForm;
301 POINT pt = { x, y };
302
303 CompForm.ptCurrentPos = pt;
304 if (editor->styleFlags & ES_MULTILINE)
305 {
306 CompForm.dwStyle = CFS_RECT;
307 CompForm.rcArea = editor->rcFormat;
308 }
309 else
310 {
311 CompForm.dwStyle = CFS_POINT;
312 SetRectEmpty(&CompForm.rcArea);
313 }
314 ImmSetCompositionWindow(hIMC, &CompForm);
315
316 fmt.cbSize = sizeof(fmt);
318
319 ZeroMemory(&lf, sizeof(lf));
321 if (fmt.dwMask & CFM_SIZE)
322 {
324 lf.lfHeight = -MulDiv(fmt.yHeight, GetDeviceCaps(hdc, LOGPIXELSY), 1440);
325 DeleteDC(hdc);
326 }
327 if (fmt.dwMask & CFM_CHARSET)
328 lf.lfCharSet = fmt.bCharSet;
329 if (fmt.dwMask & CFM_FACE)
330 lstrcpynW(lf.lfFaceName, fmt.szFaceName, ARRAY_SIZE(lf.lfFaceName));
331 ImmSetCompositionFontW(hIMC, &lf);
332
333 ImmReleaseContext(editor->hWnd, hIMC);
334 }
335 }
336#endif
337}
338
340 int nChars, BOOL bForce)
341{
342 ME_Cursor c = *start;
343 int nOfs = ME_GetCursorOfs(start), text_len = ME_GetTextLength( editor );
344 int shift = 0;
345 int totalChars = nChars;
346 ME_Paragraph *start_para;
347 BOOL delete_all = FALSE;
348
349 /* Prevent deletion past last end of paragraph run. */
350 nChars = min(nChars, text_len - nOfs);
351 if (nChars == text_len) delete_all = TRUE;
352 start_para = c.para;
353
354 if (!bForce)
355 {
356 table_protect_partial_deletion( editor, &c, &nChars );
357 if (nChars == 0) return FALSE;
358 }
359
360 while (nChars > 0)
361 {
362 ME_Run *run;
363 cursor_from_char_ofs( editor, nOfs + nChars, &c );
364 if (!c.nOffset)
365 {
366 /* We aren't deleting anything in this run, so we will go back to the
367 * last run we are deleting text in. */
368 c.run = run_prev_all_paras( c.run );
369 c.para = c.run->para;
370 c.nOffset = c.run->len;
371 }
372 run = c.run;
373 if (run->nFlags & MERF_ENDPARA)
374 {
375 int eollen = c.run->len;
376 BOOL keepFirstParaFormat;
377
378 if (!para_next( para_next( c.para ) )) return TRUE;
379
380 keepFirstParaFormat = (totalChars == nChars && nChars <= eollen &&
381 run->nCharOfs);
382 if (!editor->bEmulateVersion10) /* v4.1 */
383 {
384 ME_Paragraph *this_para = run->para;
385 ME_Paragraph *next_para = para_next( this_para );
386
387 /* The end of paragraph before a table row is only deleted if there
388 * is nothing else on the line before it. */
389 if (this_para == start_para && next_para->nFlags & MEPF_ROWSTART)
390 {
391 /* If the paragraph will be empty, then it should be deleted, however
392 * it still might have text right now which would inherit the
393 * MEPF_STARTROW property if we joined it right now.
394 * Instead we will delete it after the preceding text is deleted. */
395 if (nOfs > this_para->nCharOfs)
396 {
397 /* Skip this end of line. */
398 nChars -= (eollen < nChars) ? eollen : nChars;
399 continue;
400 }
401 keepFirstParaFormat = TRUE;
402 }
403 }
404 para_join( editor, c.para, keepFirstParaFormat );
405 /* ME_SkipAndPropagateCharOffset(p->pRun, shift); */
406 ME_CheckCharOffsets(editor);
407 nChars -= (eollen < nChars) ? eollen : nChars;
408 continue;
409 }
410 else
411 {
413 int nCharsToDelete = min(nChars, c.nOffset);
414 int i;
415
416 c.nOffset -= nCharsToDelete;
417
418 para_mark_rewrap( editor, c.run->para );
419
420 cursor = c;
421 /* nChars is the number of characters that should be deleted from the
422 PRECEDING runs (these BEFORE cursor.pRun)
423 nCharsToDelete is a number of chars to delete from THIS run */
424 nChars -= nCharsToDelete;
425 shift -= nCharsToDelete;
426 TRACE("Deleting %d (remaining %d) chars at %d in %s (%d)\n",
427 nCharsToDelete, nChars, c.nOffset,
428 debugstr_run( run ), run->len);
429
430 /* nOfs is a character offset (from the start of the document
431 to the current (deleted) run */
432 add_undo_insert_run( editor, nOfs + nChars, get_text( run, c.nOffset ), nCharsToDelete, run->nFlags, run->style );
433
434 ME_StrDeleteV(run->para->text, run->nCharOfs + c.nOffset, nCharsToDelete);
435 run->len -= nCharsToDelete;
436 TRACE("Post deletion string: %s (%d)\n", debugstr_run( run ), run->len);
437 TRACE("Shift value: %d\n", shift);
438
439 /* update cursors (including c) */
440 for (i=-1; i<editor->nCursors; i++) {
441 ME_Cursor *pThisCur = editor->pCursors + i;
442 if (i == -1) pThisCur = &c;
443 if (pThisCur->run == cursor.run) {
444 if (pThisCur->nOffset > cursor.nOffset) {
445 if (pThisCur->nOffset-cursor.nOffset < nCharsToDelete)
446 pThisCur->nOffset = cursor.nOffset;
447 else
448 pThisCur->nOffset -= nCharsToDelete;
449 assert(pThisCur->nOffset >= 0);
450 assert(pThisCur->nOffset <= run->len);
451 }
452 if (pThisCur->nOffset == run->len)
453 {
454 pThisCur->run = run_next( pThisCur->run );
455 assert( pThisCur->run );
456 pThisCur->nOffset = 0;
457 }
458 }
459 }
460
461 /* c = updated data now */
462
463 if (c.run == cursor.run) c.run->nCharOfs -= shift;
464 editor_propagate_char_ofs( editor, NULL, c.run, shift );
465
466 if (!cursor.run->len)
467 {
468 TRACE("Removing empty run\n");
469 ME_Remove( run_get_di( cursor.run ));
471 }
472
473 shift = 0;
474 continue;
475 }
476 }
477 if (delete_all) editor_set_default_para_fmt( editor, &start_para->fmt );
478 return TRUE;
479}
480
481BOOL ME_DeleteTextAtCursor(ME_TextEditor *editor, int nCursor, int nChars)
482{
483 assert(nCursor>=0 && nCursor<editor->nCursors);
484 /* text operations set modified state */
485 editor->nModifyStep = 1;
486 return ME_InternalDeleteText(editor, &editor->pCursors[nCursor],
487 nChars, FALSE);
488}
489
490static struct re_object* create_re_object(const REOBJECT *reo, ME_Run *run)
491{
492 struct re_object *reobj = malloc(sizeof(*reobj));
493
494 if (!reobj)
495 {
496 WARN("Fail to allocate re_object.\n");
497 return NULL;
498 }
499 ME_CopyReObject(&reobj->obj, reo, REO_GETOBJ_ALL_INTERFACES);
500 reobj->run = run;
501 return reobj;
502}
503
505{
506 ME_Run *run, *prev;
507 const WCHAR space = ' ';
508 struct re_object *reobj_prev = NULL;
509 ME_Cursor *cursor, cursor_from_ofs;
511 HRESULT hr;
513
514 if (editor->lpOleCallback)
515 {
516 hr = IRichEditOleCallback_QueryInsertObject(editor->lpOleCallback, (LPCLSID)&reo->clsid, reo->pstg, REO_CP_SELECTION);
517 if (hr != S_OK)
518 return hr;
519 }
520
521 extent = reo->sizel;
522 if (!extent.cx && !extent.cy && reo->poleobj)
523 {
524 hr = IOleObject_GetExtent( reo->poleobj, DVASPECT_CONTENT, &extent );
525 if (FAILED(hr))
526 {
527 extent.cx = 0;
528 extent.cy = 0;
529 }
530 }
531
532 if (reo->cp == REO_CP_SELECTION)
533 cursor = editor->pCursors;
534 else
535 {
536 cursor_from_char_ofs( editor, reo->cp, &cursor_from_ofs );
537 cursor = &cursor_from_ofs;
538 }
540
541 if (ME_IsSelection(editor))
542 ME_DeleteSelection(editor);
543
544 run = run_insert( editor, cursor, style, &space, 1, MERF_GRAPHICS );
545
546 run->reobj = create_re_object( reo, run );
547 run->reobj->obj.sizel = extent;
548
549 prev = run;
550 while ((prev = run_prev_all_paras( prev )))
551 {
552 if (prev->reobj)
553 {
554 reobj_prev = prev->reobj;
555 break;
556 }
557 }
558 if (reobj_prev)
559 list_add_after(&reobj_prev->entry, &run->reobj->entry);
560 else
561 list_add_head(&editor->reobj_list, &run->reobj->entry);
562
564 return S_OK;
565}
566
567
568void ME_InsertEndRowFromCursor(ME_TextEditor *editor, int nCursor)
569{
570 const WCHAR space = ' ';
571 ME_Cursor *cursor = editor->pCursors + nCursor;
573
574 /* FIXME no no no */
575 if (ME_IsSelection(editor))
576 ME_DeleteSelection(editor);
577
578 run_insert( editor, cursor, style, &space, 1, MERF_ENDROW );
579
581}
582
583
584void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
585 const WCHAR *str, int len, ME_Style *style)
586{
587 const WCHAR *pos;
588 ME_Cursor *cursor = editor->pCursors + nCursor;
589 int oldLen;
590
591 /* FIXME really HERE ? */
592 if (ME_IsSelection(editor))
593 ME_DeleteSelection(editor);
594
595 oldLen = ME_GetTextLength(editor);
596
597 /* text operations set modified state */
598 editor->nModifyStep = 1;
599
600 assert(style);
601
602 if (len == -1) len = lstrlenW( str );
603
604 /* grow the text limit to fit our text */
605 if (editor->nTextLimit < oldLen + len) editor->nTextLimit = oldLen + len;
606
607 pos = str;
608
609 while (len)
610 {
611 /* FIXME this sucks - no respect for unicode (what else can be a line separator in unicode?) */
612 while (pos - str < len && *pos != '\r' && *pos != '\n' && *pos != '\t')
613 pos++;
614
615 if (pos != str) /* handle text */
616 run_insert( editor, cursor, style, str, pos - str, 0 );
617 else if (*pos == '\t') /* handle tabs */
618 {
619 const WCHAR tab = '\t';
620 run_insert( editor, cursor, style, &tab, 1, MERF_TAB );
621 pos++;
622 }
623 else /* handle EOLs */
624 {
625 ME_Run *end_run, *run, *prev;
626 ME_Paragraph *new_para;
627 int eol_len = 0;
628
629 /* Check if new line is allowed for this control */
630 if (!(editor->props & TXTBIT_MULTILINE))
631 break;
632
633 /* Find number of CR and LF in end of paragraph run */
634 if (*pos =='\r')
635 {
636 if (len > 1 && pos[1] == '\n')
637 eol_len = 2;
638 else if (len > 2 && pos[1] == '\r' && pos[2] == '\n')
639 eol_len = 3;
640 else
641 eol_len = 1;
642 }
643 else
644 {
645 assert(*pos == '\n');
646 eol_len = 1;
647 }
648 pos += eol_len;
649
650 if (!editor->bEmulateVersion10 && eol_len == 3)
651 {
652 /* handle special \r\r\n sequence (richedit 2.x and higher only) */
653 const WCHAR space = ' ';
654 run_insert( editor, cursor, style, &space, 1, 0 );
655 }
656 else
657 {
658 const WCHAR cr = '\r', *eol_str = str;
659
660 if (!editor->bEmulateVersion10)
661 {
662 eol_str = &cr;
663 eol_len = 1;
664 }
665
666 if (cursor->nOffset == cursor->run->len)
667 {
668 run = run_next( cursor->run );
669 if (!run) run = cursor->run;
670 }
671 else
672 {
673 if (cursor->nOffset) run_split( editor, cursor );
674 run = cursor->run;
675 }
676
677 new_para = para_split( editor, run, style, eol_str, eol_len, 0 );
678 end_run = para_end_run( para_prev( new_para ) );
679
680 /* Move any cursors that were at the end of the previous run to the beginning of the new para */
681 prev = run_prev( end_run );
682 if (prev)
683 {
684 int i;
685 for (i = 0; i < editor->nCursors; i++)
686 {
687 if (editor->pCursors[i].run == prev &&
688 editor->pCursors[i].nOffset == prev->len)
689 {
690 editor->pCursors[i].para = new_para;
691 editor->pCursors[i].run = run;
692 editor->pCursors[i].nOffset = 0;
693 }
694 }
695 }
696
697 }
698 }
699 len -= pos - str;
700 str = pos;
701 }
702}
703
704/* Move the cursor nRelOfs characters (either forwards or backwards)
705 * If final_eop is TRUE, allow moving the cursor to the end of the final eop.
706 *
707 * returns the actual number of characters moved.
708 **/
709int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs, BOOL final_eop)
710{
711 cursor->nOffset += nRelOfs;
712 if (cursor->nOffset < 0)
713 {
714 cursor->nOffset += cursor->run->nCharOfs;
715 if (cursor->nOffset >= 0)
716 {
717 /* new offset in the same paragraph */
718 do {
719 cursor->run = run_prev( cursor->run );
720 } while (cursor->nOffset < cursor->run->nCharOfs);
721 cursor->nOffset -= cursor->run->nCharOfs;
722 return nRelOfs;
723 }
724
725 cursor->nOffset += cursor->para->nCharOfs;
726 if (cursor->nOffset <= 0)
727 {
728 /* moved to the start of the text */
729 nRelOfs -= cursor->nOffset;
731 return nRelOfs;
732 }
733
734 /* new offset in a previous paragraph */
735 do {
736 cursor->para = para_prev( cursor->para );
737 } while (cursor->nOffset < cursor->para->nCharOfs);
738 cursor->nOffset -= cursor->para->nCharOfs;
739
740 cursor->run = para_end_run( cursor->para );
741 while (cursor->nOffset < cursor->run->nCharOfs)
742 cursor->run = run_prev( cursor->run );
743 cursor->nOffset -= cursor->run->nCharOfs;
744 }
745 else if (cursor->nOffset >= cursor->run->len)
746 {
747 ME_Paragraph *next_para;
748 int new_offset;
749
750 new_offset = ME_GetCursorOfs(cursor);
751 next_para = para_next( cursor->para );
752 if (new_offset < next_para->nCharOfs)
753 {
754 /* new offset in the same paragraph */
755 do {
756 cursor->nOffset -= cursor->run->len;
757 cursor->run = run_next( cursor->run );
758 } while (cursor->nOffset >= cursor->run->len);
759 return nRelOfs;
760 }
761
762 if (new_offset >= ME_GetTextLength(editor) + (final_eop ? 1 : 0))
763 {
764 /* new offset at the end of the text */
765 ME_SetCursorToEnd(editor, cursor, final_eop);
766 nRelOfs -= new_offset - (ME_GetTextLength(editor) + (final_eop ? 1 : 0));
767 return nRelOfs;
768 }
769
770 /* new offset in a following paragraph */
771 do {
772 cursor->para = next_para;
773 next_para = para_next( next_para );
774 } while (new_offset >= next_para->nCharOfs);
775
776 cursor->nOffset = new_offset - cursor->para->nCharOfs;
777 cursor->run = para_first_run( cursor->para );
778 while (cursor->nOffset >= cursor->run->len)
779 {
780 cursor->nOffset -= cursor->run->len;
781 cursor->run = run_next( cursor->run );
782 }
783 } /* else new offset is in the same run */
784 return nRelOfs;
785}
786
787
788BOOL
790{
791 ME_Run *run = cursor->run, *other_run;
792 ME_Paragraph *para = cursor->para;
793 int nOffset = cursor->nOffset;
794
795 if (nRelOfs == -1)
796 {
797 /* Backward movement */
798 while (TRUE)
799 {
800 nOffset = ME_CallWordBreakProc( editor, get_text( run, 0 ), run->len, nOffset, WB_MOVEWORDLEFT );
801 if (nOffset) break;
802 other_run = run_prev( run );
803 if (other_run)
804 {
805 if (ME_CallWordBreakProc( editor, get_text( other_run, 0 ), other_run->len, other_run->len - 1, WB_ISDELIMITER )
806 && !(run->nFlags & MERF_ENDPARA)
807 && !(cursor->run == run && cursor->nOffset == 0)
808 && !ME_CallWordBreakProc( editor, get_text( run, 0 ), run->len, 0, WB_ISDELIMITER ))
809 break;
810 run = other_run;
811 nOffset = other_run->len;
812 }
813 else
814 {
815 if (cursor->run == run && cursor->nOffset == 0)
816 {
817 para = run->para;
818 /* Skip empty start of table row paragraph */
819 if (para_prev( para ) && para_prev( para )->nFlags & MEPF_ROWSTART)
820 para = para_prev( para );
821 /* Paragraph breaks are treated as separate words */
822 if (!para_prev( para )) return FALSE;
823 para = para_prev( para );
824 run = para_end_run( para );
825 }
826 break;
827 }
828 }
829 }
830 else
831 {
832 /* Forward movement */
833 BOOL last_delim = FALSE;
834
835 while (TRUE)
836 {
837 if (last_delim && !ME_CallWordBreakProc( editor, get_text( run, 0 ), run->len, nOffset, WB_ISDELIMITER ))
838 break;
839 nOffset = ME_CallWordBreakProc( editor, get_text( run, 0 ), run->len, nOffset, WB_MOVEWORDRIGHT );
840 if (nOffset < run->len) break;
841 other_run = run_next( run );
842 if (other_run)
843 {
844 last_delim = ME_CallWordBreakProc( editor, get_text( run, 0 ), run->len, nOffset - 1, WB_ISDELIMITER );
845 run = other_run;
846 nOffset = 0;
847 }
848 else
849 {
850 ME_Paragraph *other_para = para_next( para );
851 if (!para_next( other_para ))
852 {
853 if (cursor->run == run) return FALSE;
854 nOffset = 0;
855 break;
856 }
857 if (other_para->nFlags & MEPF_ROWSTART) other_para = para_next( other_para );
858 if (cursor->run == run) {
859 para = other_para;
860 run = para_first_run( para );
861 }
862 nOffset = 0;
863 break;
864 }
865 }
866 }
867 cursor->para = para;
868 cursor->run = run;
869 cursor->nOffset = nOffset;
870 return TRUE;
871}
872
873
874static void
876{
877 /* pCursor[0] is the end of the selection
878 * pCursor[1] is the start of the selection (or the position selection anchor)
879 * pCursor[2] and [3] are the selection anchors that are backed up
880 * so they are kept when the selection changes for drag selection.
881 */
882
883 editor->nSelectionType = selectionType;
884 switch(selectionType)
885 {
886 case stPosition:
887 break;
888 case stWord:
889 ME_MoveCursorWords(editor, &editor->pCursors[0], +1);
890 editor->pCursors[1] = editor->pCursors[0];
891 ME_MoveCursorWords(editor, &editor->pCursors[1], -1);
892 break;
893 case stParagraph:
894 editor->pCursors[1] = editor->pCursors[0];
895
896 editor->pCursors[0].run = para_end_run( editor->pCursors[0].para );
897 editor->pCursors[0].para = editor->pCursors[0].run->para;
898 editor->pCursors[0].nOffset = editor->pCursors[0].run->len;
899
900 editor->pCursors[1].run = para_first_run( editor->pCursors[1].para );
901 editor->pCursors[1].nOffset = 0;
902 break;
903 case stLine:
904 {
905 ME_Row *row = row_from_cursor( editor->pCursors );
906
907 row_first_cursor( row, editor->pCursors + 1 );
908 row_end_cursor( row, editor->pCursors, TRUE );
909 break;
910 }
911 case stDocument:
912 /* Select everything with cursor anchored from the start of the text */
913 ME_SetCursorToStart(editor, &editor->pCursors[1]);
914 ME_SetCursorToEnd(editor, &editor->pCursors[0], TRUE);
915 break;
916 default: assert(0);
917 }
918 /* Store the anchor positions for extending the selection. */
919 editor->pCursors[2] = editor->pCursors[0];
920 editor->pCursors[3] = editor->pCursors[1];
921}
922
924{
925 return cursor->para->nCharOfs + cursor->run->nCharOfs + cursor->nOffset;
926}
927
928/* Helper function for cursor_from_virtual_coords() to find paragraph within tables */
930{
931 ME_Cell *cell, *next_cell;
932
933 assert( para->nFlags & MEPF_ROWSTART );
934 cell = table_row_first_cell( para );
935 assert( cell );
936
937 /* find the cell we are in */
938 while ((next_cell = cell_next( cell )) != NULL)
939 {
940 if (x < next_cell->pt.x)
941 {
942 para = cell_first_para( cell );
943 /* Found the cell, but there might be multiple paragraphs in
944 * the cell, so need to search down the cell for the paragraph. */
945 while (cell == para_cell( para ))
946 {
947 if (y < para->pt.y + para->nHeight)
948 {
949 if (para->nFlags & MEPF_ROWSTART) return pixel_pos_in_table_row( x, y, para );
950 else return para;
951 }
952 para = para_next( para );
953 }
954 /* Past the end of the cell, so go back to the last cell paragraph */
955 return para_prev( para );
956 }
957 cell = next_cell;
958 }
959 /* Return table row delimiter */
960 para = table_row_end( para );
961 assert( para->nFlags & MEPF_ROWEND );
964 return para;
965}
966
967static BOOL row_cursor( ME_TextEditor *editor, ME_Row *row, int x,
969{
970 ME_Run *run, *last;
971 BOOL exact = TRUE;
972
973 if (x < row->pt.x)
974 {
975 x = row->pt.x;
976 exact = FALSE;
977 }
978
979 run = row_first_run( row );
980 assert( run );
981 cursor->nOffset = 0;
982 do
983 {
984 if (x >= run->pt.x && x < run->pt.x + run->nWidth)
985 {
986 cursor->nOffset = ME_CharFromPoint( editor, x - run->pt.x, run, TRUE, TRUE );
987 cursor->run = run;
988 cursor->para = run->para;
989 return exact;
990 }
991 last = run;
992 run = row_next_run( row, run );
993 } while (run);
994
995 run = last;
996
997 cursor->run = run;
998 cursor->para = run->para;
999 return FALSE;
1000}
1001
1002/* Finds the run and offset from the pixel position.
1003 *
1004 * x & y are pixel positions in virtual coordinates into the rich edit control,
1005 * so client coordinates must first be adjusted by the scroll position.
1006 *
1007 * If final_eop is TRUE consider the final end-of-paragraph.
1008 *
1009 * returns TRUE if the result was exactly under the cursor, otherwise returns
1010 * FALSE, and result is set to the closest position to the coordinates.
1011 */
1013 ME_Cursor *result, BOOL final_eop )
1014{
1015 ME_Paragraph *para = editor_first_para( editor );
1016 ME_Row *row = NULL, *next_row;
1017 BOOL isExact = TRUE;
1018
1019 x -= editor->rcFormat.left;
1020 y -= editor->rcFormat.top;
1021
1022 /* find paragraph */
1023 for (; para_next( para ); para = para_next( para ))
1024 {
1025 if (y < para->pt.y + para->nHeight)
1026 {
1027 if (para->nFlags & MEPF_ROWSTART)
1028 para = pixel_pos_in_table_row( x, y, para );
1029 y -= para->pt.y;
1030 row = para_first_row( para );
1031 break;
1032 }
1033 else if (para->nFlags & MEPF_ROWSTART)
1034 {
1035 para = table_row_end( para );
1036 }
1037 }
1038 /* find row */
1039 while (row)
1040 {
1041 if (y < row->pt.y + row->nHeight) break;
1042 next_row = row_next( row );
1043 if (!next_row) break;
1044 row = next_row;
1045 }
1046
1047 if (!row && !final_eop && para_prev( para ))
1048 {
1049 /* The position is below the last paragraph, so the last row will be used
1050 * rather than the end of the text, so the x position will be used to
1051 * determine the offset closest to the pixel position. */
1052 isExact = FALSE;
1053 row = para_end_row( para_prev( para ) );
1054 }
1055
1056 if (row) return row_cursor( editor, row, x, result ) && isExact;
1057
1058 ME_SetCursorToEnd(editor, result, TRUE);
1059 return FALSE;
1060}
1061
1062
1063/* Sets the cursor to the position closest to the pixel position
1064 *
1065 * x & y are pixel positions in client coordinates.
1066 *
1067 * return TRUE if the run is directly under the pixel
1068 * position, FALSE if it not.
1069 */
1071{
1072 x += editor->horz_si.nPos;
1073 y += editor->vert_si.nPos;
1074 return cursor_from_virtual_coords( editor, x, y, cursor, FALSE );
1075}
1076
1077
1078/* Extends the selection with a word, line, or paragraph selection type.
1079 *
1080 * The selection is anchored by editor->pCursors[2-3] such that the text
1081 * between the anchors will remain selected, and one end will be extended.
1082 *
1083 * editor->pCursors[0] should have the position to extend the selection to
1084 * before this function is called.
1085 *
1086 * Nothing will be done if editor->nSelectionType equals stPosition.
1087 */
1089{
1090 ME_Cursor tmp_cursor;
1091 int curOfs, anchorStartOfs, anchorEndOfs;
1092 if (editor->nSelectionType == stPosition || editor->nSelectionType == stDocument)
1093 return;
1094 curOfs = ME_GetCursorOfs(&editor->pCursors[0]);
1095 anchorStartOfs = ME_GetCursorOfs(&editor->pCursors[3]);
1096 anchorEndOfs = ME_GetCursorOfs(&editor->pCursors[2]);
1097
1098 tmp_cursor = editor->pCursors[0];
1099 editor->pCursors[0] = editor->pCursors[2];
1100 editor->pCursors[1] = editor->pCursors[3];
1101 if (curOfs < anchorStartOfs)
1102 {
1103 /* Extend the left side of selection */
1104 editor->pCursors[1] = tmp_cursor;
1105 switch (editor->nSelectionType)
1106 {
1107 case stWord:
1108 ME_MoveCursorWords(editor, &editor->pCursors[1], -1);
1109 break;
1110
1111 case stLine:
1112 {
1113 ME_Row *row = row_from_cursor( editor->pCursors + 1 );
1114 row_first_cursor( row, editor->pCursors + 1 );
1115 break;
1116 }
1117
1118 case stParagraph:
1119 editor->pCursors[1].run = para_first_run( editor->pCursors[1].para );
1120 editor->pCursors[1].nOffset = 0;
1121 break;
1122
1123 default:
1124 break;
1125 }
1126 }
1127 else if (curOfs >= anchorEndOfs)
1128 {
1129 /* Extend the right side of selection */
1130 editor->pCursors[0] = tmp_cursor;
1131 switch (editor->nSelectionType)
1132 {
1133 case stWord:
1134 ME_MoveCursorWords( editor, &editor->pCursors[0], +1 );
1135 break;
1136
1137 case stLine:
1138 {
1139 ME_Row *row = row_from_cursor( editor->pCursors );
1140 row_end_cursor( row, editor->pCursors, TRUE );
1141 break;
1142 }
1143
1144 case stParagraph:
1145 editor->pCursors[0].run = para_end_run( editor->pCursors[0].para );
1146 editor->pCursors[0].para = editor->pCursors[0].run->para;
1147 editor->pCursors[0].nOffset = editor->pCursors[0].run->len;
1148 break;
1149
1150 default:
1151 break;
1152 }
1153 }
1154}
1155
1156void ME_LButtonDown(ME_TextEditor *editor, int x, int y, int clickNum)
1157{
1158 ME_Cursor tmp_cursor;
1159 BOOL is_selection = FALSE, is_shift;
1160
1161 editor->nUDArrowX = -1;
1162
1163 x += editor->horz_si.nPos;
1164 y += editor->vert_si.nPos;
1165
1166 tmp_cursor = editor->pCursors[0];
1167 is_selection = ME_IsSelection(editor);
1168 is_shift = GetKeyState(VK_SHIFT) < 0;
1169
1170 cursor_from_virtual_coords( editor, x, y, &editor->pCursors[0], FALSE );
1171
1172 if (x >= editor->rcFormat.left || is_shift)
1173 {
1174 if (clickNum > 1)
1175 {
1176 editor->pCursors[1] = editor->pCursors[0];
1177 if (is_shift) {
1178 if (x >= editor->rcFormat.left)
1179 ME_SelectByType(editor, stWord);
1180 else
1182 } else if (clickNum % 2 == 0) {
1183 ME_SelectByType(editor, stWord);
1184 } else {
1186 }
1187 }
1188 else if (!is_shift)
1189 {
1190 editor->nSelectionType = stPosition;
1191 editor->pCursors[1] = editor->pCursors[0];
1192 }
1193 else if (!is_selection)
1194 {
1195 editor->nSelectionType = stPosition;
1196 editor->pCursors[1] = tmp_cursor;
1197 }
1198 else if (editor->nSelectionType != stPosition)
1199 {
1201 }
1202 }
1203 else
1204 {
1205 if (clickNum < 2) {
1206 ME_SelectByType(editor, stLine);
1207 } else if (clickNum % 2 == 0 || is_shift) {
1209 } else {
1210 ME_SelectByType(editor, stDocument);
1211 }
1212 }
1213 ME_InvalidateSelection(editor);
1214 update_caret(editor);
1215 ME_SendSelChange(editor);
1216}
1217
1218void ME_MouseMove(ME_TextEditor *editor, int x, int y)
1219{
1220 ME_Cursor tmp_cursor;
1221
1222 if (editor->nSelectionType == stDocument)
1223 return;
1224 x += editor->horz_si.nPos;
1225 y += editor->vert_si.nPos;
1226
1227 tmp_cursor = editor->pCursors[0];
1228 /* FIXME: do something with the return value of cursor_from_virtual_coords */
1229 cursor_from_virtual_coords( editor, x, y, &tmp_cursor, TRUE );
1230
1231 ME_InvalidateSelection(editor);
1232 editor->pCursors[0] = tmp_cursor;
1234
1235 if (editor->nSelectionType != stPosition &&
1236 memcmp(&editor->pCursors[1], &editor->pCursors[3], sizeof(ME_Cursor)))
1237 /* The scroll the cursor towards the other end, since it was the one
1238 * extended by ME_ExtendAnchorSelection */
1239 editor_ensure_visible( editor, &editor->pCursors[1] );
1240 else
1241 editor_ensure_visible( editor, &editor->pCursors[0] );
1242
1243 ME_InvalidateSelection(editor);
1244 update_caret(editor);
1245 ME_SendSelChange(editor);
1246}
1247
1248static int ME_GetXForArrow(ME_TextEditor *editor, ME_Cursor *pCursor)
1249{
1250 ME_Run *run = pCursor->run;
1251 int x;
1252
1253 if (editor->nUDArrowX != -1)
1254 x = editor->nUDArrowX;
1255 else
1256 {
1257 x = run->pt.x;
1258 x += ME_PointFromChar( editor, run, pCursor->nOffset, TRUE );
1259 editor->nUDArrowX = x;
1260 }
1261 return x;
1262}
1263
1264
1265static void cursor_move_line( ME_TextEditor *editor, ME_Cursor *cursor, BOOL up, BOOL extend )
1266{
1267 ME_Paragraph *old_para = cursor->para, *new_para;
1269 int x = ME_GetXForArrow( editor, cursor );
1270
1271 if (up)
1272 {
1273 /* start of the previous row */
1275 if (!row)
1276 {
1277 if (extend) ME_SetCursorToStart( editor, cursor );
1278 return;
1279 }
1280 new_para = row_para( row );
1281 if (old_para->nFlags & MEPF_ROWEND ||
1282 (para_cell( old_para ) && para_cell( old_para ) != para_cell( new_para )))
1283 {
1284 /* Brought out of a cell */
1285 new_para = para_prev( table_row_start( old_para ));
1286 if (!new_para) return; /* At the top, so don't go anywhere. */
1287 row = para_first_row( new_para );
1288 }
1289 if (new_para->nFlags & MEPF_ROWEND)
1290 {
1291 /* Brought into a table row */
1292 ME_Cell *cell = table_row_end_cell( new_para );
1293 while (x < cell->pt.x && cell_prev( cell ))
1294 cell = cell_prev( cell );
1295 if (cell_next( cell )) /* else - we are still at the end of the row */
1296 row = para_end_row( cell_end_para( cell ) );
1297 }
1298 }
1299 else
1300 {
1301 /* start of the next row */
1303 if (!row)
1304 {
1305 if (extend) ME_SetCursorToEnd( editor, cursor, TRUE );
1306 return;
1307 }
1308 new_para = row_para( row );
1309 if (old_para->nFlags & MEPF_ROWSTART ||
1310 (para_cell( old_para ) && para_cell( old_para ) != para_cell( new_para )))
1311 {
1312 /* Brought out of a cell */
1313 new_para = para_next( table_row_end( old_para ) );
1314 if (!para_next( new_para )) return; /* At the bottom, so don't go anywhere. */
1315 row = para_first_row( new_para );
1316 }
1317 if (new_para->nFlags & MEPF_ROWSTART)
1318 {
1319 /* Brought into a table row */
1320 ME_Cell *cell = table_row_first_cell( new_para );
1321 while (cell_next( cell ) && x >= cell_next( cell )->pt.x)
1322 cell = cell_next( cell );
1323 row = para_first_row( cell_first_para( cell ) );
1324 }
1325 }
1326 if (!row) return;
1327
1328 row_cursor( editor, row, x, cursor );
1329}
1330
1332{
1333 ME_Row *row = para_first_row( editor_first_para( editor ) ), *last_row;
1334 int x, yd, old_scroll_pos = editor->vert_si.nPos;
1335
1336 if (editor->vert_si.nPos < row->nHeight)
1337 {
1338 ME_SetCursorToStart( editor, cursor );
1339 /* Native clears seems to clear this x value on page up at the top
1340 * of the text, but not on page down at the end of the text.
1341 * Doesn't make sense, but we try to be bug for bug compatible. */
1342 editor->nUDArrowX = -1;
1343 }
1344 else
1345 {
1346 x = ME_GetXForArrow( editor, cursor );
1348
1349 ME_ScrollUp( editor, editor->sizeWindow.cy );
1350 /* Only move the cursor by the amount scrolled. */
1351 yd = cursor->para->pt.y + row->pt.y + editor->vert_si.nPos - old_scroll_pos;
1352 last_row = row;
1353
1354 while ((row = row_prev_all_paras( row )))
1355 {
1356 if (row_para( row )->pt.y + row->pt.y < yd) break;
1357 last_row = row;
1358 }
1359
1360 row_cursor( editor, last_row, x, cursor );
1361 }
1362}
1363
1365{
1366 ME_Row *row = para_end_row( para_prev( editor_end_para( editor ) ) ), *last_row;
1367 int x, yd, old_scroll_pos = editor->vert_si.nPos;
1368
1369 x = ME_GetXForArrow( editor, cursor );
1370
1371 if (editor->vert_si.nPos >= row_para( row )->pt.y + row->pt.y - editor->sizeWindow.cy)
1372 ME_SetCursorToEnd( editor, cursor, FALSE );
1373 else
1374 {
1376
1377 /* For native richedit controls:
1378 * v1.0 - v3.1 can only scroll down as far as the scrollbar lets us
1379 * v4.1 can scroll past this position here. */
1380 ME_ScrollDown( editor, editor->sizeWindow.cy );
1381 /* Only move the cursor by the amount scrolled. */
1382 yd = cursor->para->pt.y + row->pt.y + editor->vert_si.nPos - old_scroll_pos;
1383 last_row = row;
1384
1385 while ((row = row_next_all_paras( row )))
1386 {
1387 if (row_para( row )->pt.y + row->pt.y >= yd) break;
1388 last_row = row;
1389 }
1390
1391 row_cursor( editor, last_row, x, cursor );
1392 }
1393}
1394
1396{
1398
1400}
1401
1402static void ME_ArrowCtrlHome(ME_TextEditor *editor, ME_Cursor *pCursor)
1403{
1404 ME_SetCursorToStart(editor, pCursor);
1405}
1406
1408{
1410
1412}
1413
1414static void ME_ArrowCtrlEnd(ME_TextEditor *editor, ME_Cursor *pCursor)
1415{
1416 ME_SetCursorToEnd(editor, pCursor, FALSE);
1417}
1418
1420{
1421 return editor->pCursors[0].run != editor->pCursors[1].run ||
1422 editor->pCursors[0].nOffset != editor->pCursors[1].nOffset;
1423}
1424
1426{
1427 LONG from, to;
1428 int nStartCursor = ME_GetSelectionOfs(editor, &from, &to);
1429 int nEndCursor = nStartCursor ^ 1;
1430 ME_DeleteTextAtCursor(editor, nStartCursor, to - from);
1431 editor->pCursors[nEndCursor] = editor->pCursors[nStartCursor];
1432}
1433
1435{
1436 return style_get_insert_style( editor, editor->pCursors );
1437}
1438
1440{
1441 SELCHANGE sc;
1442
1443 sc.nmhdr.hwndFrom = NULL;
1444 sc.nmhdr.idFrom = 0;
1445 sc.nmhdr.code = EN_SELCHANGE;
1446 ME_GetSelectionOfs(editor, &sc.chrg.cpMin, &sc.chrg.cpMax);
1447 sc.seltyp = SEL_EMPTY;
1448 if (sc.chrg.cpMin != sc.chrg.cpMax)
1449 sc.seltyp |= SEL_TEXT;
1450 if (sc.chrg.cpMin < sc.chrg.cpMax+1) /* what were RICHEDIT authors thinking ? */
1451 sc.seltyp |= SEL_MULTICHAR;
1452
1453 if (sc.chrg.cpMin != editor->notified_cr.cpMin || sc.chrg.cpMax != editor->notified_cr.cpMax)
1454 {
1455 ME_ClearTempStyle(editor);
1456
1457 editor->notified_cr = sc.chrg;
1458
1459 if (editor->nEventMask & ENM_SELCHANGE)
1460 {
1461 TRACE("cpMin=%ld cpMax=%ld seltyp=%d (%s %s)\n",
1462 sc.chrg.cpMin, sc.chrg.cpMax, sc.seltyp,
1463 (sc.seltyp & SEL_TEXT) ? "SEL_TEXT" : "",
1464 (sc.seltyp & SEL_MULTICHAR) ? "SEL_MULTICHAR" : "");
1465 ITextHost_TxNotify(editor->texthost, sc.nmhdr.code, &sc);
1466 }
1467 }
1468}
1469
1470BOOL
1471ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend, BOOL ctrl)
1472{
1473 int nCursor = 0;
1474 ME_Cursor *p = &editor->pCursors[nCursor];
1475 ME_Cursor tmp_curs = *p;
1476 BOOL success = FALSE;
1477
1478 ME_CheckCharOffsets(editor);
1479 switch(nVKey) {
1480 case VK_LEFT:
1481 if (ctrl)
1482 success = ME_MoveCursorWords(editor, &tmp_curs, -1);
1483 else
1484 success = ME_MoveCursorChars(editor, &tmp_curs, -1, extend);
1485 break;
1486 case VK_RIGHT:
1487 if (ctrl)
1488 success = ME_MoveCursorWords(editor, &tmp_curs, +1);
1489 else
1490 success = ME_MoveCursorChars(editor, &tmp_curs, +1, extend);
1491 break;
1492 case VK_UP:
1493 cursor_move_line( editor, &tmp_curs, TRUE, extend );
1494 break;
1495 case VK_DOWN:
1496 cursor_move_line( editor, &tmp_curs, FALSE, extend );
1497 break;
1498 case VK_PRIOR:
1499 ME_ArrowPageUp(editor, &tmp_curs);
1500 break;
1501 case VK_NEXT:
1502 ME_ArrowPageDown(editor, &tmp_curs);
1503 break;
1504 case VK_HOME: {
1505 if (ctrl)
1506 ME_ArrowCtrlHome(editor, &tmp_curs);
1507 else
1508 ME_ArrowHome(editor, &tmp_curs);
1509 break;
1510 }
1511 case VK_END:
1512 if (ctrl)
1513 ME_ArrowCtrlEnd(editor, &tmp_curs);
1514 else
1515 ME_ArrowEnd(editor, &tmp_curs);
1516 break;
1517 }
1518
1519 if (!extend)
1520 editor->pCursors[1] = tmp_curs;
1521 *p = tmp_curs;
1522
1523 ME_InvalidateSelection(editor);
1524 ME_Repaint(editor);
1525 hide_caret(editor);
1526 editor_ensure_visible( editor, &tmp_curs );
1527 update_caret(editor);
1528 ME_SendSelChange(editor);
1529 return success;
1530}
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
Arabic default style
Definition: afstyles.h:94
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define ARRAY_SIZE(A)
Definition: main.h:20
static void list_add_head(struct list_entry *head, struct list_entry *entry)
Definition: list.h:76
#define FIXME(fmt,...)
Definition: precomp.h:53
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
#define E_INVALIDARG
Definition: ddrawi.h:101
#define malloc
Definition: debug_ros.c:4
DWORD HIMC
Definition: dimm.idl:75
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define lstrcpynW
Definition: compat.h:738
#define lstrlenW
Definition: compat.h:750
BOOL WINAPI GetCPInfo(UINT codepage, LPCPINFO cpinfo)
Definition: locale.c:2144
void ME_InsertEndRowFromCursor(ME_TextEditor *editor, int nCursor)
Definition: caret.c:568
void ME_SetCursorToStart(ME_TextEditor *editor, ME_Cursor *cursor)
Definition: caret.c:27
static void cursor_move_line(ME_TextEditor *editor, ME_Cursor *cursor, BOOL up, BOOL extend)
Definition: caret.c:1265
BOOL ME_DeleteTextAtCursor(ME_TextEditor *editor, int nCursor, int nChars)
Definition: caret.c:481
static void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *cursor)
Definition: caret.c:1395
BOOL ME_IsSelection(ME_TextEditor *editor)
Definition: caret.c:1419
void ME_DeleteSelection(ME_TextEditor *editor)
Definition: caret.c:1425
static int ME_GetXForArrow(ME_TextEditor *editor, ME_Cursor *pCursor)
Definition: caret.c:1248
static void ME_ExtendAnchorSelection(ME_TextEditor *editor)
Definition: caret.c:1088
int ME_GetCursorOfs(const ME_Cursor *cursor)
Definition: caret.c:923
void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, const WCHAR *str, int len, ME_Style *style)
Definition: caret.c:584
int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs, BOOL final_eop)
Definition: caret.c:709
static BOOL row_cursor(ME_TextEditor *editor, ME_Row *row, int x, ME_Cursor *cursor)
Definition: caret.c:967
static ME_Paragraph * pixel_pos_in_table_row(int x, int y, ME_Paragraph *para)
Definition: caret.c:929
BOOL ME_MoveCursorWords(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
Definition: caret.c:789
void ME_LButtonDown(ME_TextEditor *editor, int x, int y, int clickNum)
Definition: caret.c:1156
int ME_GetTextLengthEx(ME_TextEditor *editor, const GETTEXTLENGTHEX *how)
Definition: caret.c:91
BOOL cursor_from_coords(ME_TextEditor *editor, int x, int y, ME_Cursor *cursor)
Definition: caret.c:1070
int ME_GetSelection(ME_TextEditor *editor, ME_Cursor **from, ME_Cursor **to)
Definition: caret.c:57
BOOL ME_InternalDeleteText(ME_TextEditor *editor, ME_Cursor *start, int nChars, BOOL bForce)
Definition: caret.c:339
void hide_caret(ME_TextEditor *editor)
Definition: caret.c:267
static void ME_SelectByType(ME_TextEditor *editor, ME_SelectionType selectionType)
Definition: caret.c:875
static void ME_ArrowCtrlEnd(ME_TextEditor *editor, ME_Cursor *pCursor)
Definition: caret.c:1414
void ME_MouseMove(ME_TextEditor *editor, int x, int y)
Definition: caret.c:1218
HRESULT editor_insert_oleobj(ME_TextEditor *editor, const REOBJECT *reo)
Definition: caret.c:504
void ME_SendSelChange(ME_TextEditor *editor)
Definition: caret.c:1439
int set_selection_cursors(ME_TextEditor *editor, int from, int to)
Definition: caret.c:132
void cursor_coords(ME_TextEditor *editor, ME_Cursor *cursor, int *x, int *y, int *height)
Definition: caret.c:221
int ME_GetSelectionOfs(ME_TextEditor *editor, LONG *from, LONG *to)
Definition: caret.c:42
BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend, BOOL ctrl)
Definition: caret.c:1471
static BOOL cursor_from_virtual_coords(ME_TextEditor *editor, int x, int y, ME_Cursor *result, BOOL final_eop)
Definition: caret.c:1012
static void ME_SetCursorToEnd(ME_TextEditor *editor, ME_Cursor *cursor, BOOL final_eop)
Definition: caret.c:34
void create_caret(ME_TextEditor *editor)
Definition: caret.c:251
int ME_GetTextLength(ME_TextEditor *editor)
Definition: caret.c:83
void show_caret(ME_TextEditor *editor)
Definition: caret.c:261
static void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *cursor)
Definition: caret.c:1331
static struct re_object * create_re_object(const REOBJECT *reo, ME_Run *run)
Definition: caret.c:490
static void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *cursor)
Definition: caret.c:1364
void update_caret(ME_TextEditor *editor)
Definition: caret.c:277
static void ME_ArrowCtrlHome(ME_TextEditor *editor, ME_Cursor *pCursor)
Definition: caret.c:1402
ME_Style * ME_GetSelectionInsertStyle(ME_TextEditor *editor)
Definition: caret.c:1434
static void ME_ArrowEnd(ME_TextEditor *editor, ME_Cursor *cursor)
Definition: caret.c:1407
void ME_DestroyContext(ME_Context *c)
Definition: context.c:44
void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC)
Definition: context.c:23
ME_Paragraph * editor_first_para(ME_TextEditor *editor)
Definition: editor.c:276
ME_Paragraph * editor_end_para(ME_TextEditor *editor)
Definition: editor.c:282
struct png_info_def *typedef unsigned char **typedef struct png_info_def *typedef struct png_info_def *typedef struct png_info_def *typedef unsigned char ** row
Definition: typeof.h:78
#define assert(x)
Definition: debug.h:53
#define pt(x, y)
Definition: drawing.c:79
void ME_InvalidateSelection(ME_TextEditor *editor)
Definition: paint.c:1253
ME_Row * para_first_row(ME_Paragraph *para)
Definition: para.c:132
ME_Run * run_next(ME_Run *run)
Definition: run.c:68
void editor_set_default_para_fmt(ME_TextEditor *editor, PARAFORMAT2 *pFmt)
Definition: para.c:958
void ME_Remove(ME_DisplayItem *diWhere)
Definition: list.c:35
ME_Style * style_get_insert_style(ME_TextEditor *editor, ME_Cursor *cursor)
Definition: style.c:476
ME_Cell * table_row_end_cell(ME_Paragraph *para)
Definition: table.c:178
int ME_PointFromCharContext(ME_Context *c, ME_Run *pRun, int nOffset, BOOL visual_order)
Definition: run.c:613
ME_Paragraph * cell_first_para(ME_Cell *cell)
Definition: table.c:202
ME_Cell * cell_next(ME_Cell *cell)
Definition: table.c:192
void ME_ReleaseStyle(ME_Style *item)
Definition: style.c:462
ME_Cell * cell_prev(ME_Cell *cell)
Definition: table.c:197
ME_Row * row_from_cursor(ME_Cursor *cursor)
Definition: row.c:74
#define ITextHost_TxCreateCaret(This, a, b, c)
Definition: editor.h:340
void editor_propagate_char_ofs(ME_TextEditor *editor, ME_Paragraph *para, ME_Run *run, int shift)
Definition: run.c:147
ME_Paragraph * row_para(ME_Row *row)
Definition: row.c:103
ME_Row * para_end_row(ME_Paragraph *para)
Definition: para.c:141
void ME_Repaint(ME_TextEditor *editor)
Definition: paint.c:121
ME_Run * run_insert(ME_TextEditor *editor, ME_Cursor *cursor, ME_Style *style, const WCHAR *str, int len, int flags)
Definition: run.c:380
ME_Run * run_prev(ME_Run *run)
Definition: run.c:82
ME_Paragraph * para_split(ME_TextEditor *editor, ME_Run *run, ME_Style *style, const WCHAR *eol_str, int eol_len, int paraFlags)
Definition: para.c:538
void ME_CopyReObject(REOBJECT *dst, const REOBJECT *src, DWORD flags)
Definition: richole.c:5919
void row_first_cursor(ME_Row *row, ME_Cursor *cursor)
Definition: row.c:82
#define ITextHost_TxNotify(This, a, b)
Definition: editor.h:367
ME_Run * para_end_run(ME_Paragraph *para)
Definition: para.c:117
void ME_ScrollDown(ME_TextEditor *editor, int cy)
Definition: paint.c:1136
#define ITextHost_TxSetCaretPos(This, a, b)
Definition: editor.h:342
ME_Cell * table_row_first_cell(ME_Paragraph *para)
Definition: table.c:170
ME_Cell * para_cell(ME_Paragraph *para)
Definition: para.c:127
static ME_DisplayItem * run_get_di(ME_Run *run)
Definition: editor.h:162
ME_Paragraph * table_row_end(ME_Paragraph *para)
Definition: table.c:127
#define ITextHost_TxGetDC(This)
Definition: editor.h:332
ME_Run * row_first_run(ME_Row *row)
Definition: row.c:54
ME_Run * run_prev_all_paras(ME_Run *run)
Definition: run.c:110
ME_Paragraph * para_join(ME_TextEditor *editor, ME_Paragraph *para, BOOL use_first_fmt)
Definition: para.c:681
ME_Row * row_prev_all_paras(ME_Row *row)
Definition: row.c:45
void table_protect_partial_deletion(ME_TextEditor *editor, ME_Cursor *c, int *num_chars)
Definition: table.c:217
int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset, BOOL visual_order)
Definition: run.c:654
void row_end_cursor(ME_Row *row, ME_Cursor *cursor, BOOL include_eop)
Definition: row.c:92
ME_Run * row_next_run(ME_Row *row, ME_Run *run)
Definition: row.c:63
#define ITextHost_TxReleaseDC(This, a)
Definition: editor.h:333
void ME_StrDeleteV(ME_String *s, int nVChar, int nChars)
Definition: string.c:147
ME_Row * row_next_all_paras(ME_Row *row)
Definition: row.c:36
void para_mark_rewrap(ME_TextEditor *editor, ME_Paragraph *para)
Definition: para.c:26
ME_Run * para_first_run(ME_Paragraph *para)
Definition: para.c:104
ME_Paragraph * table_row_start(ME_Paragraph *para)
Definition: table.c:142
void cursor_from_char_ofs(ME_TextEditor *editor, int char_ofs, ME_Cursor *cursor)
Definition: run.c:245
ME_Paragraph * para_prev(ME_Paragraph *para)
Definition: para.c:63
void ME_ClearTempStyle(ME_TextEditor *editor)
Definition: style.c:507
ME_Row * row_next(ME_Row *row)
Definition: row.c:27
int ME_CallWordBreakProc(ME_TextEditor *editor, WCHAR *str, INT len, INT start, INT code)
Definition: string.c:204
void ME_ScrollUp(ME_TextEditor *editor, int cy)
Definition: paint.c:1131
BOOL add_undo_insert_run(ME_TextEditor *, int pos, const WCHAR *str, int len, int flags, ME_Style *style)
Definition: undo.c:131
ME_Paragraph * cell_end_para(ME_Cell *cell)
Definition: table.c:207
ME_Run * run_split(ME_TextEditor *editor, ME_Cursor *cursor)
Definition: run.c:310
static WCHAR * get_text(const ME_Run *run, int offset)
Definition: editor.h:41
void ME_GetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
Definition: run.c:858
void ME_DestroyDisplayItem(ME_DisplayItem *item)
Definition: list.c:115
void ME_CheckCharOffsets(ME_TextEditor *editor)
Definition: run.c:178
ME_Paragraph * para_next(ME_Paragraph *para)
Definition: para.c:57
#define ITextHost_TxShowCaret(This, a)
Definition: editor.h:341
void editor_ensure_visible(ME_TextEditor *editor, ME_Cursor *cursor)
Definition: paint.c:1210
int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run, BOOL closest, BOOL visual_order)
Definition: run.c:575
static const char * debugstr_run(const ME_Run *run)
Definition: editor.h:46
#define MERF_TAB
Definition: editstr.h:105
#define MERF_ENDPARA
Definition: editstr.h:120
#define MERF_GRAPHICS
Definition: editstr.h:103
#define MEPF_ROWSTART
Definition: editstr.h:142
#define MEPF_ROWEND
Definition: editstr.h:143
#define MEPF_REWRAP
Definition: editstr.h:139
ME_SelectionType
Definition: editstr.h:362
@ stWord
Definition: editstr.h:364
@ stParagraph
Definition: editstr.h:366
@ stPosition
Definition: editstr.h:363
@ stLine
Definition: editstr.h:365
@ stDocument
Definition: editstr.h:367
#define MERF_ENDROW
Definition: editstr.h:122
unsigned int BOOL
Definition: ntddk_ex.h:94
GLuint start
Definition: gl.h:1545
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLuint GLuint end
Definition: gl.h:1545
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
const GLubyte * c
Definition: glext.h:8905
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLuint64EXT * result
Definition: glext.h:11304
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define up(mutex)
Definition: glue.h:30
const char cursor[]
Definition: icontest.c:13
BOOL WINAPI ImmSetCompositionFontW(_In_ HIMC hIMC, _In_ LPLOGFONTW lplf)
Definition: ime.c:1322
#define CFS_RECT
Definition: imm.h:324
BOOL WINAPI ImmSetCompositionWindow(_In_ HIMC hIMC, _In_ LPCOMPOSITIONFORM lpCompForm)
Definition: ime.c:1149
HIMC WINAPI ImmGetContext(_In_ HWND hWnd)
Definition: imm.c:1065
#define CFS_POINT
Definition: imm.h:325
BOOL WINAPI ImmReleaseContext(_In_ HWND hWnd, _In_ HIMC hIMC)
Definition: imm.c:1109
BOOL WINAPI ImmIsIME(_In_ HKL hKL)
Definition: ime.c:429
#define S_OK
Definition: intsafe.h:52
#define FAILED(hr)
Definition: intsafe.h:51
#define c
Definition: ke_i.h:80
HDC hdc
Definition: main.c:9
static HDC
Definition: imagelist.c:88
static UINT UINT last
Definition: font.c:45
#define shift
Definition: input.c:1755
#define ctrl
Definition: input.c:1756
#define min(a, b)
Definition: monoChain.cc:55
INT WINAPI MulDiv(INT nNumber, INT nNumerator, INT nDenominator)
Definition: muldiv.c:25
long LONG
Definition: pedump.c:60
#define ES_MULTILINE
Definition: pedump.c:667
#define swap(a, b)
Definition: qsort.c:63
#define WB_MOVEWORDRIGHT
Definition: richedit.h:1002
#define SEL_EMPTY
Definition: richedit.h:822
#define GTL_CLOSE
Definition: richedit.h:1057
#define SEL_MULTICHAR
Definition: richedit.h:825
#define EN_SELCHANGE
Definition: richedit.h:193
#define GTL_NUMCHARS
Definition: richedit.h:1058
#define SEL_TEXT
Definition: richedit.h:823
#define ENM_SELCHANGE
Definition: richedit.h:478
#define CFM_CHARSET
Definition: richedit.h:358
#define CFM_SIZE
Definition: richedit.h:362
#define GTL_PRECISE
Definition: richedit.h:1056
#define PFM_TABLEROWDELIMITER
Definition: richedit.h:868
#define CFM_FACE
Definition: richedit.h:360
#define GTL_NUMBYTES
Definition: richedit.h:1059
#define WB_MOVEWORDLEFT
Definition: richedit.h:1000
#define PFE_TABLEROWDELIMITER
Definition: richedit.h:942
#define GTL_USECRLF
Definition: richedit.h:1055
const WCHAR * str
__WINE_SERVER_LIST_INLINE void list_add_after(struct list *elem, struct list *to_add)
Definition: list.h:78
HRESULT hr
Definition: shlfolder.c:183
#define TRACE(s)
Definition: solgame.cpp:4
CardRegion * from
Definition: spigame.cpp:19
RECT rcArea
Definition: dimm.idl:88
DWORD dwStyle
Definition: dimm.idl:86
POINT ptCurrentPos
Definition: dimm.idl:87
LONG lfHeight
Definition: dimm.idl:59
WCHAR lfFaceName[LF_FACESIZE]
Definition: dimm.idl:72
BYTE lfCharSet
Definition: dimm.idl:67
LONG cy
Definition: kdterminal.h:28
LONG cpMax
Definition: richedit.h:501
LONG cpMin
Definition: richedit.h:500
UINT MaxCharSize
Definition: winnls.h:601
DWORD dwMask
Definition: richedit.h:667
WORD wEffects
Definition: richedit.h:669
CLSID clsid
Definition: richole.idl:60
LPSTORAGE pstg
Definition: richole.idl:62
LPOLEOBJECT poleobj
Definition: richole.idl:61
LONG cp
Definition: richole.idl:59
SIZEL sizel
Definition: richole.idl:64
NMHDR nmhdr
Definition: richedit.h:685
WORD seltyp
Definition: richedit.h:687
CHARRANGE chrg
Definition: richedit.h:686
Definition: dsound.c:943
struct list entry
Definition: editstr.h:153
struct tagME_Run * run
Definition: editstr.h:155
REOBJECT obj
Definition: editstr.h:154
ME_Paragraph * para
Definition: editstr.h:275
int nOffset
Definition: editstr.h:277
ME_Run * run
Definition: editstr.h:276
PARAFORMAT2 fmt
Definition: editstr.h:204
int nAscent
Definition: editstr.h:166
POINT pt
Definition: editstr.h:167
int nCharOfs
Definition: editstr.h:162
int nDescent
Definition: editstr.h:166
struct tagME_Paragraph * para
Definition: editstr.h:161
ME_Style * style
Definition: editstr.h:160
struct re_object * reobj
Definition: editstr.h:168
int nFlags
Definition: editstr.h:165
int len
Definition: editstr.h:163
SCROLLINFO vert_si
Definition: editstr.h:449
ITextHost2 * texthost
Definition: editstr.h:391
struct list reobj_list
Definition: editstr.h:459
ME_SelectionType nSelectionType
Definition: editstr.h:443
ME_Cursor * pCursors
Definition: editstr.h:396
LPRICHEDITOLECALLBACK lpOleCallback
Definition: editstr.h:427
SCROLLINFO horz_si
Definition: editstr.h:449
CHARRANGE notified_cr
Definition: editstr.h:446
BOOL caret_hidden
Definition: editstr.h:454
unsigned int bEmulateVersion10
Definition: editstr.h:392
UINT_PTR idFrom
Definition: winuser.h:3234
UINT code
Definition: winuser.h:3235
HWND hwndFrom
Definition: winuser.h:3233
long y
Definition: polytest.cpp:48
long x
Definition: polytest.cpp:48
LONG right
Definition: windef.h:308
LONG top
Definition: windef.h:307
LONG left
Definition: windef.h:306
#define TXTBIT_MULTILINE
Definition: textserv.h:186
static struct wctab tab[]
#define success(from, fromstr, to, tostr)
#define ZeroMemory
Definition: winbase.h:1753
int WINAPI GetDeviceCaps(_In_opt_ HDC, _In_ int)
#define LOGPIXELSY
Definition: wingdi.h:719
HDC WINAPI CreateCompatibleDC(_In_opt_ HDC hdc)
#define DEFAULT_CHARSET
Definition: wingdi.h:384
BOOL WINAPI DeleteDC(_In_ HDC)
HKL WINAPI GetKeyboardLayout(_In_ DWORD)
#define WB_ISDELIMITER
Definition: winuser.h:549
#define VK_UP
Definition: winuser.h:2244
#define VK_NEXT
Definition: winuser.h:2240
#define VK_END
Definition: winuser.h:2241
#define VK_HOME
Definition: winuser.h:2242
BOOL WINAPI SetRectEmpty(_Out_ LPRECT)
#define VK_LEFT
Definition: winuser.h:2243
#define VK_RIGHT
Definition: winuser.h:2245
#define VK_DOWN
Definition: winuser.h:2246
#define VK_SHIFT
Definition: winuser.h:2221
#define VK_PRIOR
Definition: winuser.h:2239
SHORT WINAPI GetKeyState(_In_ int)
__wchar_t WCHAR
Definition: xmlstorage.h:180