ReactOS  0.4.13-dev-92-gf251225
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->pPara = editor->pBuffer->pFirst->member.para.next_para;
30  cursor->pRun = ME_FindItemFwd(cursor->pPara, diRun);
31  cursor->nOffset = 0;
32 }
33 
34 static void ME_SetCursorToEnd(ME_TextEditor *editor, ME_Cursor *cursor, BOOL final_eop)
35 {
36  cursor->pPara = editor->pBuffer->pLast->member.para.prev_para;
37  cursor->pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
38  cursor->nOffset = final_eop ? cursor->pRun->member.run.len : 0;
39 }
40 
41 
42 int ME_GetSelectionOfs(ME_TextEditor *editor, int *from, int *to)
43 {
44  *from = ME_GetCursorOfs(&editor->pCursors[0]);
45  *to = ME_GetCursorOfs(&editor->pCursors[1]);
46 
47  if (*from > *to)
48  {
49  int 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 {
86  ME_SetCursorToEnd(editor, &cursor, FALSE);
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->styleFlags & ES_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 int ME_SetSelection(ME_TextEditor *editor, int from, int to)
127 {
128  int selectionEnd = 0;
129  const int len = ME_GetTextLength(editor);
130 
131  /* all negative values are effectively the same */
132  if (from < 0)
133  from = -1;
134  if (to < 0)
135  to = -1;
136 
137  /* select all */
138  if (from == 0 && to == -1)
139  {
140  ME_SetCursorToStart(editor, &editor->pCursors[1]);
141  ME_SetCursorToEnd(editor, &editor->pCursors[0], TRUE);
142  ME_InvalidateSelection(editor);
143  return len + 1;
144  }
145 
146  /* if both values are equal and also out of bound, that means to */
147  /* put the selection at the end of the text */
148  if ((from == to) && (to < 0 || to > len))
149  {
150  selectionEnd = 1;
151  }
152  else
153  {
154  /* if from is negative and to is positive then selection is */
155  /* deselected and caret moved to end of the current selection */
156  if (from < 0)
157  {
158  int start, end;
159  ME_GetSelectionOfs(editor, &start, &end);
160  if (start != end)
161  {
162  if (end > len)
163  {
164  editor->pCursors[0].nOffset = 0;
165  end --;
166  }
167  editor->pCursors[1] = editor->pCursors[0];
168  ME_Repaint(editor);
169  }
170  return end;
171  }
172 
173  /* adjust to if it's a negative value */
174  if (to < 0)
175  to = len + 1;
176 
177  /* flip from and to if they are reversed */
178  if (from>to)
179  {
180  int tmp = from;
181  from = to;
182  to = tmp;
183  }
184 
185  /* after fiddling with the values, we find from > len && to > len */
186  if (from > len)
187  selectionEnd = 1;
188  /* special case with to too big */
189  else if (to > len)
190  to = len + 1;
191  }
192 
193  if (selectionEnd)
194  {
195  ME_SetCursorToEnd(editor, &editor->pCursors[0], FALSE);
196  editor->pCursors[1] = editor->pCursors[0];
197  ME_InvalidateSelection(editor);
198  return len;
199  }
200 
201  ME_CursorFromCharOfs(editor, from, &editor->pCursors[1]);
202  editor->pCursors[0] = editor->pCursors[1];
203  ME_MoveCursorChars(editor, &editor->pCursors[0], to - from, FALSE);
204  /* Selection is not allowed in the middle of an end paragraph run. */
205  if (editor->pCursors[1].pRun->member.run.nFlags & MERF_ENDPARA)
206  editor->pCursors[1].nOffset = 0;
207  if (editor->pCursors[0].pRun->member.run.nFlags & MERF_ENDPARA)
208  {
209  if (to > len)
210  editor->pCursors[0].nOffset = editor->pCursors[0].pRun->member.run.len;
211  else
212  editor->pCursors[0].nOffset = 0;
213  }
214  return to;
215 }
216 
217 
219  int *x, int *y, int *height)
220 {
222  ME_DisplayItem *run = pCursor->pRun;
223  ME_DisplayItem *para = pCursor->pPara;
224  ME_DisplayItem *pSizeRun = run;
225  ME_Context c;
226  int run_x;
227 
228  assert(height && x && y);
229  assert(~para->member.para.nFlags & MEPF_REWRAP);
230  assert(run && run->type == diRun);
231  assert(para && para->type == diParagraph);
232 
234  assert(row && row->type == diStartRow);
235 
236  ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost));
237 
238  if (!pCursor->nOffset)
239  {
241  assert(prev);
242  if (prev->type == diRun)
243  pSizeRun = prev;
244  }
245  if (editor->bCaretAtEnd && !pCursor->nOffset &&
246  run == ME_FindItemFwd(row, diRun))
247  {
249  assert(tmp);
250  if (tmp->type == diRun)
251  {
253  pSizeRun = run = tmp;
254  assert(run);
255  assert(run->type == diRun);
256  }
257  }
258  run_x = ME_PointFromCharContext( &c, &run->member.run, pCursor->nOffset, TRUE );
259 
260  *height = pSizeRun->member.run.nAscent + pSizeRun->member.run.nDescent;
261  *x = c.rcView.left + run->member.run.pt.x + run_x - editor->horz_si.nPos;
262  *y = c.rcView.top + para->member.para.pt.y + row->member.row.nBaseline
263  + run->member.run.pt.y - pSizeRun->member.run.nAscent
264  - editor->vert_si.nPos;
266  return;
267 }
268 
269 
270 void
272 {
273  int x, y, height;
274 
275  ME_GetCursorCoordinates(editor, &editor->pCursors[0], &x, &y, &height);
276  if(editor->bHaveFocus && !ME_IsSelection(editor))
277  {
278  x = min(x, editor->rcFormat.right-1);
280  ITextHost_TxSetCaretPos(editor->texthost, x, y);
281  }
282 }
283 
284 
286 {
287  ME_MoveCaret(ed);
288  if(ed->bHaveFocus && !ME_IsSelection(ed))
289  ITextHost_TxShowCaret(ed->texthost, TRUE);
290 }
291 
293 {
294  if(!ed->bHaveFocus || ME_IsSelection(ed))
295  {
296  ITextHost_TxShowCaret(ed->texthost, FALSE);
297  DestroyCaret();
298  }
299 }
300 
302  int nChars, BOOL bForce)
303 {
304  ME_Cursor c = *start;
305  int nOfs = ME_GetCursorOfs(start), text_len = ME_GetTextLength( editor );
306  int shift = 0;
307  int totalChars = nChars;
308  ME_DisplayItem *start_para;
309  BOOL delete_all = FALSE;
310 
311  /* Prevent deletion past last end of paragraph run. */
312  nChars = min(nChars, text_len - nOfs);
313  if (nChars == text_len) delete_all = TRUE;
314  start_para = c.pPara;
315 
316  if (!bForce)
317  {
318  ME_ProtectPartialTableDeletion(editor, &c, &nChars);
319  if (nChars == 0)
320  return FALSE;
321  }
322 
323  while(nChars > 0)
324  {
325  ME_Run *run;
326  ME_CursorFromCharOfs(editor, nOfs+nChars, &c);
327  if (!c.nOffset &&
328  nOfs+nChars == (c.pRun->member.run.nCharOfs
329  + c.pPara->member.para.nCharOfs))
330  {
331  /* We aren't deleting anything in this run, so we will go back to the
332  * last run we are deleting text in. */
333  ME_PrevRun(&c.pPara, &c.pRun, TRUE);
334  c.nOffset = c.pRun->member.run.len;
335  }
336  run = &c.pRun->member.run;
337  if (run->nFlags & MERF_ENDPARA) {
338  int eollen = c.pRun->member.run.len;
339  BOOL keepFirstParaFormat;
340 
341  if (!ME_FindItemFwd(c.pRun, diParagraph))
342  {
343  return TRUE;
344  }
345  keepFirstParaFormat = (totalChars == nChars && nChars <= eollen &&
346  run->nCharOfs);
347  if (!editor->bEmulateVersion10) /* v4.1 */
348  {
349  ME_DisplayItem *next_para = ME_FindItemFwd(c.pRun, diParagraphOrEnd);
350  ME_DisplayItem *this_para = next_para->member.para.prev_para;
351 
352  /* The end of paragraph before a table row is only deleted if there
353  * is nothing else on the line before it. */
354  if (this_para == start_para &&
355  next_para->member.para.nFlags & MEPF_ROWSTART)
356  {
357  /* If the paragraph will be empty, then it should be deleted, however
358  * it still might have text right now which would inherit the
359  * MEPF_STARTROW property if we joined it right now.
360  * Instead we will delete it after the preceding text is deleted. */
361  if (nOfs > this_para->member.para.nCharOfs) {
362  /* Skip this end of line. */
363  nChars -= (eollen < nChars) ? eollen : nChars;
364  continue;
365  }
366  keepFirstParaFormat = TRUE;
367  }
368  }
369  ME_JoinParagraphs(editor, c.pPara, keepFirstParaFormat);
370  /* ME_SkipAndPropagateCharOffset(p->pRun, shift); */
371  ME_CheckCharOffsets(editor);
372  nChars -= (eollen < nChars) ? eollen : nChars;
373  continue;
374  }
375  else
376  {
378  int nCharsToDelete = min(nChars, c.nOffset);
379  int i;
380 
381  c.nOffset -= nCharsToDelete;
382 
384 
385  cursor = c;
386  /* nChars is the number of characters that should be deleted from the
387  PRECEDING runs (these BEFORE cursor.pRun)
388  nCharsToDelete is a number of chars to delete from THIS run */
389  nChars -= nCharsToDelete;
390  shift -= nCharsToDelete;
391  TRACE("Deleting %d (remaining %d) chars at %d in %s (%d)\n",
392  nCharsToDelete, nChars, c.nOffset,
393  debugstr_run( run ), run->len);
394 
395  /* nOfs is a character offset (from the start of the document
396  to the current (deleted) run */
397  add_undo_insert_run( editor, nOfs + nChars, get_text( run, c.nOffset ), nCharsToDelete, run->nFlags, run->style );
398 
399  ME_StrDeleteV(run->para->text, run->nCharOfs + c.nOffset, nCharsToDelete);
400  run->len -= nCharsToDelete;
401  TRACE("Post deletion string: %s (%d)\n", debugstr_run( run ), run->len);
402  TRACE("Shift value: %d\n", shift);
403 
404  /* update cursors (including c) */
405  for (i=-1; i<editor->nCursors; i++) {
406  ME_Cursor *pThisCur = editor->pCursors + i;
407  if (i == -1) pThisCur = &c;
408  if (pThisCur->pRun == cursor.pRun) {
409  if (pThisCur->nOffset > cursor.nOffset) {
410  if (pThisCur->nOffset-cursor.nOffset < nCharsToDelete)
411  pThisCur->nOffset = cursor.nOffset;
412  else
413  pThisCur->nOffset -= nCharsToDelete;
414  assert(pThisCur->nOffset >= 0);
415  assert(pThisCur->nOffset <= run->len);
416  }
417  if (pThisCur->nOffset == run->len)
418  {
419  pThisCur->pRun = ME_FindItemFwd(pThisCur->pRun, diRunOrParagraphOrEnd);
420  assert(pThisCur->pRun->type == diRun);
421  pThisCur->nOffset = 0;
422  }
423  }
424  }
425 
426  /* c = updated data now */
427 
428  if (c.pRun == cursor.pRun)
430  else
432 
433  if (!cursor.pRun->member.run.len)
434  {
435  TRACE("Removing empty run\n");
436  ME_Remove(cursor.pRun);
438  }
439 
440  shift = 0;
441  /*
442  ME_CheckCharOffsets(editor);
443  */
444  continue;
445  }
446  }
447  if (delete_all) ME_SetDefaultParaFormat( editor, &start_para->member.para.fmt );
448  return TRUE;
449 }
450 
451 BOOL ME_DeleteTextAtCursor(ME_TextEditor *editor, int nCursor, int nChars)
452 {
453  assert(nCursor>=0 && nCursor<editor->nCursors);
454  /* text operations set modified state */
455  editor->nModifyStep = 1;
456  return ME_InternalDeleteText(editor, &editor->pCursors[nCursor],
457  nChars, FALSE);
458 }
459 
460 static ME_DisplayItem *
462  const WCHAR *str, int len, ME_Style *style,
463  int flags)
464 {
465  ME_Cursor *p = &editor->pCursors[nCursor];
466 
467  editor->bCaretAtEnd = FALSE;
468 
469  assert(p->pRun->type == diRun);
470 
471  return ME_InsertRunAtCursor(editor, p, style, str, len, flags);
472 }
473 
474 static struct re_object* create_re_object(const REOBJECT *reo)
475 {
476  struct re_object *reobj = heap_alloc(sizeof(*reobj));
477 
478  if (!reobj)
479  {
480  WARN("Fail to allocate re_object.\n");
481  return NULL;
482  }
483  ME_CopyReObject(&reobj->obj, reo, REO_GETOBJ_ALL_INTERFACES);
484  return reobj;
485 }
486 
487 void ME_InsertOLEFromCursor(ME_TextEditor *editor, const REOBJECT* reo, int nCursor)
488 {
489  ME_Style *pStyle = ME_GetInsertStyle(editor, nCursor);
490  ME_DisplayItem *di;
491  WCHAR space = ' ';
492  ME_DisplayItem *di_prev = NULL;
493  struct re_object *reobj_prev = NULL;
494 
495  /* FIXME no no no */
496  if (ME_IsSelection(editor))
497  ME_DeleteSelection(editor);
498 
499  di = ME_InternalInsertTextFromCursor(editor, nCursor, &space, 1, pStyle,
500  MERF_GRAPHICS);
501  di->member.run.reobj = create_re_object(reo);
502 
503  di_prev = di;
504  while (ME_PrevRun(NULL, &di_prev, TRUE))
505  {
506  if (di_prev->member.run.reobj)
507  {
508  reobj_prev = di_prev->member.run.reobj;
509  break;
510  }
511  }
512  if (reobj_prev)
513  list_add_after(&reobj_prev->entry, &di->member.run.reobj->entry);
514  else
515  list_add_head(&editor->reobj_list, &di->member.run.reobj->entry);
516 
517  ME_ReleaseStyle(pStyle);
518 }
519 
520 
521 void ME_InsertEndRowFromCursor(ME_TextEditor *editor, int nCursor)
522 {
523  ME_Style *pStyle = ME_GetInsertStyle(editor, nCursor);
524  WCHAR space = ' ';
525 
526  /* FIXME no no no */
527  if (ME_IsSelection(editor))
528  ME_DeleteSelection(editor);
529 
530  ME_InternalInsertTextFromCursor(editor, nCursor, &space, 1, pStyle,
531  MERF_ENDROW);
532  ME_ReleaseStyle(pStyle);
533 }
534 
535 
536 void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
537  const WCHAR *str, int len, ME_Style *style)
538 {
539  const WCHAR *pos;
540  ME_Cursor *p = NULL;
541  int oldLen;
542 
543  /* FIXME really HERE ? */
544  if (ME_IsSelection(editor))
545  ME_DeleteSelection(editor);
546 
547  /* FIXME: is this too slow? */
548  /* Didn't affect performance for WM_SETTEXT (around 50sec/30K) */
549  oldLen = ME_GetTextLength(editor);
550 
551  /* text operations set modified state */
552  editor->nModifyStep = 1;
553 
554  assert(style);
555 
556  assert(nCursor>=0 && nCursor<editor->nCursors);
557  if (len == -1)
558  len = lstrlenW(str);
559 
560  /* grow the text limit to fit our text */
561  if(editor->nTextLimit < oldLen +len)
562  editor->nTextLimit = oldLen + len;
563 
564  pos = str;
565 
566  while (len)
567  {
568  /* FIXME this sucks - no respect for unicode (what else can be a line separator in unicode?) */
569  while(pos - str < len && *pos != '\r' && *pos != '\n' && *pos != '\t')
570  pos++;
571 
572  if (pos != str) { /* handle text */
573  ME_InternalInsertTextFromCursor(editor, nCursor, str, pos-str, style, 0);
574  } else if (*pos == '\t') { /* handle tabs */
575  WCHAR tab = '\t';
576  ME_InternalInsertTextFromCursor(editor, nCursor, &tab, 1, style, MERF_TAB);
577  pos++;
578  } else { /* handle EOLs */
579  ME_DisplayItem *tp, *end_run, *run, *prev;
580  int eol_len = 0;
581 
582  /* Check if new line is allowed for this control */
583  if (!(editor->styleFlags & ES_MULTILINE))
584  break;
585 
586  /* Find number of CR and LF in end of paragraph run */
587  if (*pos =='\r')
588  {
589  if (len > 1 && pos[1] == '\n')
590  eol_len = 2;
591  else if (len > 2 && pos[1] == '\r' && pos[2] == '\n')
592  eol_len = 3;
593  else
594  eol_len = 1;
595  } else {
596  assert(*pos == '\n');
597  eol_len = 1;
598  }
599  pos += eol_len;
600 
601  if (!editor->bEmulateVersion10 && eol_len == 3)
602  {
603  /* handle special \r\r\n sequence (richedit 2.x and higher only) */
604  WCHAR space = ' ';
605  ME_InternalInsertTextFromCursor(editor, nCursor, &space, 1, style, 0);
606  } else {
607  const WCHAR cr = '\r', *eol_str = str;
608 
609  if (!editor->bEmulateVersion10)
610  {
611  eol_str = &cr;
612  eol_len = 1;
613  }
614 
615  p = &editor->pCursors[nCursor];
616 
617  if (p->nOffset == p->pRun->member.run.len)
618  {
619  run = ME_FindItemFwd( p->pRun, diRun );
620  if (!run) run = p->pRun;
621  }
622  else
623  {
624  if (p->nOffset) ME_SplitRunSimple(editor, p);
625  run = p->pRun;
626  }
627 
628  tp = ME_SplitParagraph(editor, run, style, eol_str, eol_len, 0);
629 
630  end_run = ME_FindItemBack(tp, diRun);
631 
632  /* Move any cursors that were at the end of the previous run to the beginning of the new para */
633  prev = ME_FindItemBack( end_run, diRun );
634  if (prev)
635  {
636  int i;
637  for (i = 0; i < editor->nCursors; i++)
638  {
639  if (editor->pCursors[i].pRun == prev &&
640  editor->pCursors[i].nOffset == prev->member.run.len)
641  {
642  editor->pCursors[i].pPara = tp;
643  editor->pCursors[i].pRun = run;
644  editor->pCursors[i].nOffset = 0;
645  }
646  }
647  }
648 
649  }
650  }
651  len -= pos - str;
652  str = pos;
653  }
654 }
655 
656 /* Move the cursor nRelOfs characters (either forwards or backwards)
657  * If final_eop is TRUE, allow moving the cursor to the end of the final eop.
658  *
659  * returns the actual number of characters moved.
660  **/
661 int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs, BOOL final_eop)
662 {
663  cursor->nOffset += nRelOfs;
664  if (cursor->nOffset < 0)
665  {
666  cursor->nOffset += cursor->pRun->member.run.nCharOfs;
667  if (cursor->nOffset >= 0)
668  {
669  /* new offset in the same paragraph */
670  do {
671  cursor->pRun = ME_FindItemBack(cursor->pRun, diRun);
672  } while (cursor->nOffset < cursor->pRun->member.run.nCharOfs);
673  cursor->nOffset -= cursor->pRun->member.run.nCharOfs;
674  return nRelOfs;
675  }
676 
677  cursor->nOffset += cursor->pPara->member.para.nCharOfs;
678  if (cursor->nOffset <= 0)
679  {
680  /* moved to the start of the text */
681  nRelOfs -= cursor->nOffset;
682  ME_SetCursorToStart(editor, cursor);
683  return nRelOfs;
684  }
685 
686  /* new offset in a previous paragraph */
687  do {
688  cursor->pPara = cursor->pPara->member.para.prev_para;
689  } while (cursor->nOffset < cursor->pPara->member.para.nCharOfs);
690  cursor->nOffset -= cursor->pPara->member.para.nCharOfs;
691 
692  cursor->pRun = ME_FindItemBack(cursor->pPara->member.para.next_para, diRun);
693  while (cursor->nOffset < cursor->pRun->member.run.nCharOfs) {
694  cursor->pRun = ME_FindItemBack(cursor->pRun, diRun);
695  }
696  cursor->nOffset -= cursor->pRun->member.run.nCharOfs;
697  } else if (cursor->nOffset >= cursor->pRun->member.run.len) {
698  ME_DisplayItem *next_para;
699  int new_offset;
700 
701  new_offset = ME_GetCursorOfs(cursor);
702  next_para = cursor->pPara->member.para.next_para;
703  if (new_offset < next_para->member.para.nCharOfs)
704  {
705  /* new offset in the same paragraph */
706  do {
707  cursor->nOffset -= cursor->pRun->member.run.len;
708  cursor->pRun = ME_FindItemFwd(cursor->pRun, diRun);
709  } while (cursor->nOffset >= cursor->pRun->member.run.len);
710  return nRelOfs;
711  }
712 
713  if (new_offset >= ME_GetTextLength(editor) + (final_eop ? 1 : 0))
714  {
715  /* new offset at the end of the text */
716  ME_SetCursorToEnd(editor, cursor, final_eop);
717  nRelOfs -= new_offset - (ME_GetTextLength(editor) + (final_eop ? 1 : 0));
718  return nRelOfs;
719  }
720 
721  /* new offset in a following paragraph */
722  do {
723  cursor->pPara = next_para;
724  next_para = next_para->member.para.next_para;
725  } while (new_offset >= next_para->member.para.nCharOfs);
726 
727  cursor->nOffset = new_offset - cursor->pPara->member.para.nCharOfs;
728  cursor->pRun = ME_FindItemFwd(cursor->pPara, diRun);
729  while (cursor->nOffset >= cursor->pRun->member.run.len)
730  {
731  cursor->nOffset -= cursor->pRun->member.run.len;
732  cursor->pRun = ME_FindItemFwd(cursor->pRun, diRun);
733  }
734  } /* else new offset is in the same run */
735  return nRelOfs;
736 }
737 
738 
739 BOOL
741 {
742  ME_DisplayItem *pRun = cursor->pRun, *pOtherRun;
743  ME_DisplayItem *pPara = cursor->pPara;
744  int nOffset = cursor->nOffset;
745 
746  if (nRelOfs == -1)
747  {
748  /* Backward movement */
749  while (TRUE)
750  {
751  nOffset = ME_CallWordBreakProc(editor, get_text( &pRun->member.run, 0 ),
752  pRun->member.run.len, nOffset, WB_MOVEWORDLEFT);
753  if (nOffset)
754  break;
755  pOtherRun = ME_FindItemBack(pRun, diRunOrParagraph);
756  if (pOtherRun->type == diRun)
757  {
758  if (ME_CallWordBreakProc(editor, get_text( &pOtherRun->member.run, 0 ),
759  pOtherRun->member.run.len,
760  pOtherRun->member.run.len - 1,
762  && !(pRun->member.run.nFlags & MERF_ENDPARA)
763  && !(cursor->pRun == pRun && cursor->nOffset == 0)
764  && !ME_CallWordBreakProc(editor, get_text( &pRun->member.run, 0 ),
765  pRun->member.run.len, 0,
767  break;
768  pRun = pOtherRun;
769  nOffset = pOtherRun->member.run.len;
770  }
771  else if (pOtherRun->type == diParagraph)
772  {
773  if (cursor->pRun == pRun && cursor->nOffset == 0)
774  {
775  pPara = pOtherRun;
776  /* Skip empty start of table row paragraph */
777  if (pPara->member.para.prev_para->member.para.nFlags & MEPF_ROWSTART)
778  pPara = pPara->member.para.prev_para;
779  /* Paragraph breaks are treated as separate words */
780  if (pPara->member.para.prev_para->type == diTextStart)
781  return FALSE;
782 
783  pRun = ME_FindItemBack(pPara, diRun);
784  pPara = pPara->member.para.prev_para;
785  }
786  break;
787  }
788  }
789  }
790  else
791  {
792  /* Forward movement */
793  BOOL last_delim = FALSE;
794 
795  while (TRUE)
796  {
797  if (last_delim && !ME_CallWordBreakProc(editor, get_text( &pRun->member.run, 0 ),
798  pRun->member.run.len, nOffset, WB_ISDELIMITER))
799  break;
800  nOffset = ME_CallWordBreakProc(editor, get_text( &pRun->member.run, 0 ),
801  pRun->member.run.len, nOffset, WB_MOVEWORDRIGHT);
802  if (nOffset < pRun->member.run.len)
803  break;
804  pOtherRun = ME_FindItemFwd(pRun, diRunOrParagraphOrEnd);
805  if (pOtherRun->type == diRun)
806  {
807  last_delim = ME_CallWordBreakProc(editor, get_text( &pRun->member.run, 0 ),
808  pRun->member.run.len, nOffset - 1, WB_ISDELIMITER);
809  pRun = pOtherRun;
810  nOffset = 0;
811  }
812  else if (pOtherRun->type == diParagraph)
813  {
814  if (pOtherRun->member.para.nFlags & MEPF_ROWSTART)
815  pOtherRun = pOtherRun->member.para.next_para;
816  if (cursor->pRun == pRun) {
817  pPara = pOtherRun;
818  pRun = ME_FindItemFwd(pPara, diRun);
819  }
820  nOffset = 0;
821  break;
822  }
823  else /* diTextEnd */
824  {
825  if (cursor->pRun == pRun)
826  return FALSE;
827  nOffset = 0;
828  break;
829  }
830  }
831  }
832  cursor->pPara = pPara;
833  cursor->pRun = pRun;
834  cursor->nOffset = nOffset;
835  return TRUE;
836 }
837 
838 
839 static void
841 {
842  /* pCursor[0] is the end of the selection
843  * pCursor[1] is the start of the selection (or the position selection anchor)
844  * pCursor[2] and [3] are the selection anchors that are backed up
845  * so they are kept when the selection changes for drag selection.
846  */
847 
848  editor->nSelectionType = selectionType;
849  switch(selectionType)
850  {
851  case stPosition:
852  break;
853  case stWord:
854  ME_MoveCursorWords(editor, &editor->pCursors[0], +1);
855  editor->pCursors[1] = editor->pCursors[0];
856  ME_MoveCursorWords(editor, &editor->pCursors[1], -1);
857  break;
858  case stLine:
859  case stParagraph:
860  {
861  ME_DisplayItem *pItem;
862  ME_DIType fwdSearchType, backSearchType;
863  if (selectionType == stParagraph) {
864  backSearchType = diParagraph;
865  fwdSearchType = diParagraphOrEnd;
866  } else {
867  backSearchType = diStartRow;
868  fwdSearchType = diStartRowOrParagraphOrEnd;
869  }
870  pItem = ME_FindItemFwd(editor->pCursors[0].pRun, fwdSearchType);
871  assert(pItem);
872  if (pItem->type == diTextEnd)
873  editor->pCursors[0].pRun = ME_FindItemBack(pItem, diRun);
874  else
875  editor->pCursors[0].pRun = ME_FindItemFwd(pItem, diRun);
876  editor->pCursors[0].pPara = ME_GetParagraph(editor->pCursors[0].pRun);
877  editor->pCursors[0].nOffset = 0;
878 
879  pItem = ME_FindItemBack(pItem, backSearchType);
880  editor->pCursors[1].pRun = ME_FindItemFwd(pItem, diRun);
881  editor->pCursors[1].pPara = ME_GetParagraph(editor->pCursors[1].pRun);
882  editor->pCursors[1].nOffset = 0;
883  break;
884  }
885  case stDocument:
886  /* Select everything with cursor anchored from the start of the text */
887  editor->nSelectionType = stDocument;
888  ME_SetCursorToStart(editor, &editor->pCursors[1]);
889  ME_SetCursorToEnd(editor, &editor->pCursors[0], FALSE);
890  break;
891  default: assert(0);
892  }
893  /* Store the anchor positions for extending the selection. */
894  editor->pCursors[2] = editor->pCursors[0];
895  editor->pCursors[3] = editor->pCursors[1];
896 }
897 
899 {
900  return cursor->pPara->member.para.nCharOfs
901  + cursor->pRun->member.run.nCharOfs + cursor->nOffset;
902 }
903 
904 /* Helper function for ME_FindPixelPos to find paragraph within tables */
906  ME_DisplayItem *para)
907 {
908  ME_DisplayItem *cell, *next_cell;
910  cell = para->member.para.next_para->member.para.pCell;
911  assert(cell);
912 
913  /* find the cell we are in */
914  while ((next_cell = cell->member.cell.next_cell) != NULL) {
915  if (x < next_cell->member.cell.pt.x)
916  {
917  para = ME_FindItemFwd(cell, diParagraph);
918  /* Found the cell, but there might be multiple paragraphs in
919  * the cell, so need to search down the cell for the paragraph. */
920  while (cell == para->member.para.pCell) {
921  if (y < para->member.para.pt.y + para->member.para.nHeight)
922  {
923  if (para->member.para.nFlags & MEPF_ROWSTART)
924  return ME_FindPixelPosInTableRow(x, y, para);
925  else
926  return para;
927  }
928  para = para->member.para.next_para;
929  }
930  /* Past the end of the cell, so go back to the last cell paragraph */
931  return para->member.para.prev_para;
932  }
933  cell = next_cell;
934  }
935  /* Return table row delimiter */
936  para = ME_FindItemFwd(cell, diParagraph);
940  return para;
941 }
942 
944  int x, ME_Cursor *cursor, BOOL *pbCaretAtEnd)
945 {
946  ME_DisplayItem *pNext, *pLastRun;
947  ME_Row *row = &pRow->member.row;
948  BOOL exact = TRUE;
949 
950  if (x < row->pt.x)
951  {
952  x = row->pt.x;
953  exact = FALSE;
954  }
955  pNext = ME_FindItemFwd(pRow, diRunOrStartRow);
956  assert(pNext->type == diRun);
957  if (pbCaretAtEnd) *pbCaretAtEnd = FALSE;
958  cursor->nOffset = 0;
959  do {
960  int run_x = pNext->member.run.pt.x;
961  int width = pNext->member.run.nWidth;
962 
963  if (x >= run_x && x < run_x+width)
964  {
965  cursor->nOffset = ME_CharFromPoint(editor, x-run_x, &pNext->member.run, TRUE, TRUE);
966  cursor->pRun = pNext;
967  cursor->pPara = ME_GetParagraph( cursor->pRun );
968  return exact;
969  }
970  pLastRun = pNext;
971  pNext = ME_FindItemFwd(pNext, diRunOrStartRow);
972  } while(pNext && pNext->type == diRun);
973 
974  if ((pLastRun->member.run.nFlags & MERF_ENDPARA) == 0)
975  {
976  cursor->pRun = ME_FindItemFwd(pNext, diRun);
977  if (pbCaretAtEnd) *pbCaretAtEnd = TRUE;
978  }
979  else
980  cursor->pRun = pLastRun;
981 
982  cursor->pPara = ME_GetParagraph( cursor->pRun );
983  return FALSE;
984 }
985 
986 /* Finds the run and offset from the pixel position.
987  *
988  * x & y are pixel positions in virtual coordinates into the rich edit control,
989  * so client coordinates must first be adjusted by the scroll position.
990  *
991  * If final_eop is TRUE consider the final end-of-paragraph.
992  *
993  * returns TRUE if the result was exactly under the cursor, otherwise returns
994  * FALSE, and result is set to the closest position to the coordinates.
995  */
996 static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y,
997  ME_Cursor *result, BOOL *is_eol, BOOL final_eop)
998 {
1000  BOOL isExact = TRUE;
1001 
1002  x -= editor->rcFormat.left;
1003  y -= editor->rcFormat.top;
1004 
1005  if (is_eol)
1006  *is_eol = FALSE;
1007 
1008  /* find paragraph */
1009  for (; p != editor->pBuffer->pLast; p = p->member.para.next_para)
1010  {
1011  assert(p->type == diParagraph);
1012  if (y < p->member.para.pt.y + p->member.para.nHeight)
1013  {
1014  if (p->member.para.nFlags & MEPF_ROWSTART)
1016  y -= p->member.para.pt.y;
1018  break;
1019  } else if (p->member.para.nFlags & MEPF_ROWSTART) {
1020  p = ME_GetTableRowEnd(p);
1021  }
1022  }
1023  /* find row */
1024  for (; p != editor->pBuffer->pLast; )
1025  {
1026  ME_DisplayItem *pp;
1027  assert(p->type == diStartRow);
1028  if (y < p->member.row.pt.y + p->member.row.nHeight) break;
1030  if (!pp) break;
1031  p = pp;
1032  }
1033  if (p == editor->pBuffer->pLast && !final_eop)
1034  {
1035  /* The position is below the last paragraph, so the last row will be used
1036  * rather than the end of the text, so the x position will be used to
1037  * determine the offset closest to the pixel position. */
1038  isExact = FALSE;
1040  if (!p) p = editor->pBuffer->pLast;
1041  }
1042 
1043  assert( p->type == diStartRow || p == editor->pBuffer->pLast );
1044 
1045  if( p->type == diStartRow )
1046  return ME_FindRunInRow( editor, p, x, result, is_eol ) && isExact;
1047 
1048  ME_SetCursorToEnd(editor, result, TRUE);
1049  return FALSE;
1050 }
1051 
1052 
1053 /* Sets the cursor to the position closest to the pixel position
1054  *
1055  * x & y are pixel positions in client coordinates.
1056  *
1057  * isExact will be set to TRUE if the run is directly under the pixel
1058  * position, FALSE if it not, unless isExact is set to NULL.
1059  *
1060  * return FALSE if outside client area and the cursor is not set,
1061  * otherwise TRUE is returned.
1062  */
1064  ME_Cursor *cursor, BOOL *isExact)
1065 {
1066  RECT rc;
1067  BOOL bResult;
1068 
1069  ITextHost_TxGetClientRect(editor->texthost, &rc);
1070  if (x < 0 || y < 0 || x >= rc.right || y >= rc.bottom) {
1071  if (isExact) *isExact = FALSE;
1072  return FALSE;
1073  }
1074  x += editor->horz_si.nPos;
1075  y += editor->vert_si.nPos;
1076  bResult = ME_FindPixelPos(editor, x, y, cursor, NULL, FALSE);
1077  if (isExact) *isExact = bResult;
1078  return TRUE;
1079 }
1080 
1081 
1082 
1083 /* Extends the selection with a word, line, or paragraph selection type.
1084  *
1085  * The selection is anchored by editor->pCursors[2-3] such that the text
1086  * between the anchors will remain selected, and one end will be extended.
1087  *
1088  * editor->pCursors[0] should have the position to extend the selection to
1089  * before this function is called.
1090  *
1091  * Nothing will be done if editor->nSelectionType equals stPosition.
1092  */
1094 {
1095  ME_Cursor tmp_cursor;
1096  int curOfs, anchorStartOfs, anchorEndOfs;
1097  if (editor->nSelectionType == stPosition || editor->nSelectionType == stDocument)
1098  return;
1099  curOfs = ME_GetCursorOfs(&editor->pCursors[0]);
1100  anchorStartOfs = ME_GetCursorOfs(&editor->pCursors[3]);
1101  anchorEndOfs = ME_GetCursorOfs(&editor->pCursors[2]);
1102 
1103  tmp_cursor = editor->pCursors[0];
1104  editor->pCursors[0] = editor->pCursors[2];
1105  editor->pCursors[1] = editor->pCursors[3];
1106  if (curOfs < anchorStartOfs)
1107  {
1108  /* Extend the left side of selection */
1109  editor->pCursors[1] = tmp_cursor;
1110  if (editor->nSelectionType == stWord)
1111  ME_MoveCursorWords(editor, &editor->pCursors[1], -1);
1112  else
1113  {
1114  ME_DisplayItem *pItem;
1115  ME_DIType searchType = ((editor->nSelectionType == stLine) ?
1117  pItem = ME_FindItemBack(editor->pCursors[1].pRun, searchType);
1118  editor->pCursors[1].pRun = ME_FindItemFwd(pItem, diRun);
1119  editor->pCursors[1].pPara = ME_GetParagraph(editor->pCursors[1].pRun);
1120  editor->pCursors[1].nOffset = 0;
1121  }
1122  }
1123  else if (curOfs >= anchorEndOfs)
1124  {
1125  /* Extend the right side of selection */
1126  editor->pCursors[0] = tmp_cursor;
1127  if (editor->nSelectionType == stWord)
1128  ME_MoveCursorWords(editor, &editor->pCursors[0], +1);
1129  else
1130  {
1131  ME_DisplayItem *pItem;
1132  ME_DIType searchType = ((editor->nSelectionType == stLine) ?
1134  pItem = ME_FindItemFwd(editor->pCursors[0].pRun, searchType);
1135  if (pItem->type == diTextEnd)
1136  editor->pCursors[0].pRun = ME_FindItemBack(pItem, diRun);
1137  else
1138  editor->pCursors[0].pRun = ME_FindItemFwd(pItem, diRun);
1139  editor->pCursors[0].pPara = ME_GetParagraph(editor->pCursors[0].pRun);
1140  editor->pCursors[0].nOffset = 0;
1141  }
1142  }
1143 }
1144 
1145 void ME_LButtonDown(ME_TextEditor *editor, int x, int y, int clickNum)
1146 {
1147  ME_Cursor tmp_cursor;
1148  BOOL is_selection = FALSE, is_shift;
1149 
1150  editor->nUDArrowX = -1;
1151 
1152  x += editor->horz_si.nPos;
1153  y += editor->vert_si.nPos;
1154 
1155  tmp_cursor = editor->pCursors[0];
1156  is_selection = ME_IsSelection(editor);
1157  is_shift = GetKeyState(VK_SHIFT) < 0;
1158 
1159  ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd, FALSE);
1160 
1161  if (x >= editor->rcFormat.left || is_shift)
1162  {
1163  if (clickNum > 1)
1164  {
1165  editor->pCursors[1] = editor->pCursors[0];
1166  if (is_shift) {
1167  if (x >= editor->rcFormat.left)
1168  ME_SelectByType(editor, stWord);
1169  else
1170  ME_SelectByType(editor, stParagraph);
1171  } else if (clickNum % 2 == 0) {
1172  ME_SelectByType(editor, stWord);
1173  } else {
1174  ME_SelectByType(editor, stParagraph);
1175  }
1176  }
1177  else if (!is_shift)
1178  {
1179  editor->nSelectionType = stPosition;
1180  editor->pCursors[1] = editor->pCursors[0];
1181  }
1182  else if (!is_selection)
1183  {
1184  editor->nSelectionType = stPosition;
1185  editor->pCursors[1] = tmp_cursor;
1186  }
1187  else if (editor->nSelectionType != stPosition)
1188  {
1189  ME_ExtendAnchorSelection(editor);
1190  }
1191  }
1192  else
1193  {
1194  if (clickNum < 2) {
1195  ME_SelectByType(editor, stLine);
1196  } else if (clickNum % 2 == 0 || is_shift) {
1197  ME_SelectByType(editor, stParagraph);
1198  } else {
1199  ME_SelectByType(editor, stDocument);
1200  }
1201  }
1202  ME_InvalidateSelection(editor);
1204  ME_ShowCaret(editor);
1205  ME_SendSelChange(editor);
1206 }
1207 
1208 void ME_MouseMove(ME_TextEditor *editor, int x, int y)
1209 {
1210  ME_Cursor tmp_cursor;
1211 
1212  if (editor->nSelectionType == stDocument)
1213  return;
1214  x += editor->horz_si.nPos;
1215  y += editor->vert_si.nPos;
1216 
1217  tmp_cursor = editor->pCursors[0];
1218  /* FIXME: do something with the return value of ME_FindPixelPos */
1219  ME_FindPixelPos(editor, x, y, &tmp_cursor, &editor->bCaretAtEnd, TRUE);
1220 
1221  ME_InvalidateSelection(editor);
1222  editor->pCursors[0] = tmp_cursor;
1223  ME_ExtendAnchorSelection(editor);
1224 
1225  if (editor->nSelectionType != stPosition &&
1226  memcmp(&editor->pCursors[1], &editor->pCursors[3], sizeof(ME_Cursor)))
1227  {
1228  /* The scroll the cursor towards the other end, since it was the one
1229  * extended by ME_ExtendAnchorSelection */
1230  ME_EnsureVisible(editor, &editor->pCursors[1]);
1231  } else {
1232  ME_EnsureVisible(editor, &editor->pCursors[0]);
1233  }
1234 
1235  ME_InvalidateSelection(editor);
1237  ME_ShowCaret(editor);
1238  ME_SendSelChange(editor);
1239 }
1240 
1241 static int ME_GetXForArrow(ME_TextEditor *editor, ME_Cursor *pCursor)
1242 {
1243  ME_DisplayItem *pRun = pCursor->pRun;
1244  int x;
1245 
1246  if (editor->nUDArrowX != -1)
1247  x = editor->nUDArrowX;
1248  else {
1249  if (editor->bCaretAtEnd)
1250  {
1251  pRun = ME_FindItemBack(pRun, diRun);
1252  assert(pRun);
1253  x = pRun->member.run.pt.x + pRun->member.run.nWidth;
1254  }
1255  else {
1256  x = pRun->member.run.pt.x;
1257  x += ME_PointFromChar(editor, &pRun->member.run, pCursor->nOffset, TRUE);
1258  }
1259  editor->nUDArrowX = x;
1260  }
1261  return x;
1262 }
1263 
1264 
1265 static void
1266 ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs, BOOL extend)
1267 {
1268  ME_DisplayItem *pRun = pCursor->pRun;
1269  ME_DisplayItem *pOldPara = pCursor->pPara;
1270  ME_DisplayItem *pItem, *pNewPara;
1271  int x = ME_GetXForArrow(editor, pCursor);
1272 
1273  if (editor->bCaretAtEnd && !pCursor->nOffset)
1274  if (!ME_PrevRun(&pOldPara, &pRun, TRUE))
1275  return;
1276 
1277  if (nRelOfs == -1)
1278  {
1279  /* start of this row */
1280  pItem = ME_FindItemBack(pRun, diStartRow);
1281  assert(pItem);
1282  /* start of the previous row */
1283  pItem = ME_FindItemBack(pItem, diStartRow);
1284  if (!pItem) /* row not found */
1285  {
1286  if (extend)
1287  ME_SetCursorToStart(editor, pCursor);
1288  return;
1289  }
1290  pNewPara = ME_GetParagraph(pItem);
1291  if (pOldPara->member.para.nFlags & MEPF_ROWEND ||
1292  (pOldPara->member.para.pCell &&
1293  pOldPara->member.para.pCell != pNewPara->member.para.pCell))
1294  {
1295  /* Brought out of a cell */
1296  pNewPara = ME_GetTableRowStart(pOldPara)->member.para.prev_para;
1297  if (pNewPara->type == diTextStart)
1298  return; /* At the top, so don't go anywhere. */
1299  pItem = ME_FindItemFwd(pNewPara, diStartRow);
1300  }
1301  if (pNewPara->member.para.nFlags & MEPF_ROWEND)
1302  {
1303  /* Brought into a table row */
1304  ME_Cell *cell = &ME_FindItemBack(pNewPara, diCell)->member.cell;
1305  while (x < cell->pt.x && cell->prev_cell)
1306  cell = &cell->prev_cell->member.cell;
1307  if (cell->next_cell) /* else - we are still at the end of the row */
1308  pItem = ME_FindItemBack(cell->next_cell, diStartRow);
1309  }
1310  }
1311  else
1312  {
1313  /* start of the next row */
1314  pItem = ME_FindItemFwd(pRun, diStartRow);
1315  if (!pItem) /* row not found */
1316  {
1317  if (extend)
1318  ME_SetCursorToEnd(editor, pCursor, TRUE);
1319  return;
1320  }
1321  pNewPara = ME_GetParagraph(pItem);
1322  if (pOldPara->member.para.nFlags & MEPF_ROWSTART ||
1323  (pOldPara->member.para.pCell &&
1324  pOldPara->member.para.pCell != pNewPara->member.para.pCell))
1325  {
1326  /* Brought out of a cell */
1327  pNewPara = ME_GetTableRowEnd(pOldPara)->member.para.next_para;
1328  if (pNewPara->type == diTextEnd)
1329  return; /* At the bottom, so don't go anywhere. */
1330  pItem = ME_FindItemFwd(pNewPara, diStartRow);
1331  }
1332  if (pNewPara->member.para.nFlags & MEPF_ROWSTART)
1333  {
1334  /* Brought into a table row */
1335  ME_DisplayItem *cell = ME_FindItemFwd(pNewPara, diCell);
1336  while (cell->member.cell.next_cell &&
1337  x >= cell->member.cell.next_cell->member.cell.pt.x)
1338  cell = cell->member.cell.next_cell;
1339  pItem = ME_FindItemFwd(cell, diStartRow);
1340  }
1341  }
1342  if (!pItem)
1343  {
1344  /* row not found - ignore */
1345  return;
1346  }
1347  ME_FindRunInRow(editor, pItem, x, pCursor, &editor->bCaretAtEnd);
1348  assert(pCursor->pRun);
1349  assert(pCursor->pRun->type == diRun);
1350 }
1351 
1352 static void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
1353 {
1355 
1356  if (editor->vert_si.nPos < p->member.row.nHeight)
1357  {
1358  ME_SetCursorToStart(editor, pCursor);
1359  editor->bCaretAtEnd = FALSE;
1360  /* Native clears seems to clear this x value on page up at the top
1361  * of the text, but not on page down at the end of the text.
1362  * Doesn't make sense, but we try to be bug for bug compatible. */
1363  editor->nUDArrowX = -1;
1364  } else {
1365  ME_DisplayItem *pRun = pCursor->pRun;
1366  ME_DisplayItem *pLast;
1367  int x, y, yd, yp;
1368  int yOldScrollPos = editor->vert_si.nPos;
1369 
1370  x = ME_GetXForArrow(editor, pCursor);
1371  if (!pCursor->nOffset && editor->bCaretAtEnd)
1372  pRun = ME_FindItemBack(pRun, diRun);
1373 
1375  assert(p->type == diStartRow);
1377  y = yp + p->member.row.pt.y;
1378 
1379  ME_ScrollUp(editor, editor->sizeWindow.cy);
1380  /* Only move the cursor by the amount scrolled. */
1381  yd = y + editor->vert_si.nPos - yOldScrollPos;
1382  pLast = p;
1383 
1384  do {
1386  if (!p)
1387  break;
1388  if (p->type == diParagraph) { /* crossing paragraphs */
1389  if (p->member.para.prev_para == NULL)
1390  break;
1391  yp = p->member.para.prev_para->member.para.pt.y;
1392  continue;
1393  }
1394  y = yp + p->member.row.pt.y;
1395  if (y < yd)
1396  break;
1397  pLast = p;
1398  } while(1);
1399 
1400  ME_FindRunInRow(editor, pLast, x, pCursor, &editor->bCaretAtEnd);
1401  }
1402  assert(pCursor->pRun);
1403  assert(pCursor->pRun->type == diRun);
1404 }
1405 
1406 static void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
1407 {
1408  ME_DisplayItem *pLast;
1409  int x, y;
1410 
1411  /* Find y position of the last row */
1412  pLast = editor->pBuffer->pLast;
1413  y = pLast->member.para.prev_para->member.para.pt.y
1414  + ME_FindItemBack(pLast, diStartRow)->member.row.pt.y;
1415 
1416  x = ME_GetXForArrow(editor, pCursor);
1417 
1418  if (editor->vert_si.nPos >= y - editor->sizeWindow.cy)
1419  {
1420  ME_SetCursorToEnd(editor, pCursor, FALSE);
1421  editor->bCaretAtEnd = FALSE;
1422  } else {
1423  ME_DisplayItem *pRun = pCursor->pRun;
1424  ME_DisplayItem *p;
1425  int yd, yp;
1426  int yOldScrollPos = editor->vert_si.nPos;
1427 
1428  if (!pCursor->nOffset && editor->bCaretAtEnd)
1429  pRun = ME_FindItemBack(pRun, diRun);
1430 
1432  assert(p->type == diStartRow);
1434  y = yp + p->member.row.pt.y;
1435 
1436  /* For native richedit controls:
1437  * v1.0 - v3.1 can only scroll down as far as the scrollbar lets us
1438  * v4.1 can scroll past this position here. */
1439  ME_ScrollDown(editor, editor->sizeWindow.cy);
1440  /* Only move the cursor by the amount scrolled. */
1441  yd = y + editor->vert_si.nPos - yOldScrollPos;
1442  pLast = p;
1443 
1444  do {
1446  if (!p)
1447  break;
1448  if (p->type == diParagraph) {
1449  yp = p->member.para.pt.y;
1450  continue;
1451  }
1452  y = yp + p->member.row.pt.y;
1453  if (y >= yd)
1454  break;
1455  pLast = p;
1456  } while(1);
1457 
1458  ME_FindRunInRow(editor, pLast, x, pCursor, &editor->bCaretAtEnd);
1459  }
1460  assert(pCursor->pRun);
1461  assert(pCursor->pRun->type == diRun);
1462 }
1463 
1464 static void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
1465 {
1466  ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diStartRow);
1467  if (pRow) {
1468  ME_DisplayItem *pRun;
1469  if (editor->bCaretAtEnd && !pCursor->nOffset) {
1470  pRow = ME_FindItemBack(pRow, diStartRow);
1471  if (!pRow)
1472  return;
1473  }
1474  pRun = ME_FindItemFwd(pRow, diRun);
1475  if (pRun) {
1476  pCursor->pRun = pRun;
1477  assert(pCursor->pPara == ME_GetParagraph(pRun));
1478  pCursor->nOffset = 0;
1479  }
1480  }
1481  editor->bCaretAtEnd = FALSE;
1482 }
1483 
1484 static void ME_ArrowCtrlHome(ME_TextEditor *editor, ME_Cursor *pCursor)
1485 {
1486  ME_SetCursorToStart(editor, pCursor);
1487  editor->bCaretAtEnd = FALSE;
1488 }
1489 
1490 static void ME_ArrowEnd(ME_TextEditor *editor, ME_Cursor *pCursor)
1491 {
1492  ME_DisplayItem *pRow;
1493 
1494  if (editor->bCaretAtEnd && !pCursor->nOffset)
1495  return;
1496 
1498  assert(pRow);
1499  if (pRow->type == diStartRow) {
1500  ME_DisplayItem *pRun = ME_FindItemFwd(pRow, diRun);
1501  assert(pRun);
1502  pCursor->pRun = pRun;
1503  assert(pCursor->pPara == ME_GetParagraph(pCursor->pRun));
1504  pCursor->nOffset = 0;
1505  editor->bCaretAtEnd = TRUE;
1506  return;
1507  }
1508  pCursor->pRun = ME_FindItemBack(pRow, diRun);
1509  assert(pCursor->pRun && pCursor->pRun->member.run.nFlags & MERF_ENDPARA);
1510  assert(pCursor->pPara == ME_GetParagraph(pCursor->pRun));
1511  pCursor->nOffset = 0;
1512  editor->bCaretAtEnd = FALSE;
1513 }
1514 
1515 static void ME_ArrowCtrlEnd(ME_TextEditor *editor, ME_Cursor *pCursor)
1516 {
1517  ME_SetCursorToEnd(editor, pCursor, FALSE);
1518  editor->bCaretAtEnd = FALSE;
1519 }
1520 
1522 {
1523  return editor->pCursors[0].pRun != editor->pCursors[1].pRun ||
1524  editor->pCursors[0].nOffset != editor->pCursors[1].nOffset;
1525 }
1526 
1528 {
1529  int from, to;
1530  int nStartCursor = ME_GetSelectionOfs(editor, &from, &to);
1531  int nEndCursor = nStartCursor ^ 1;
1532  ME_DeleteTextAtCursor(editor, nStartCursor, to - from);
1533  editor->pCursors[nEndCursor] = editor->pCursors[nStartCursor];
1534 }
1535 
1537 {
1538  return ME_GetInsertStyle(editor, 0);
1539 }
1540 
1542 {
1543  SELCHANGE sc;
1544 
1545  sc.nmhdr.hwndFrom = NULL;
1546  sc.nmhdr.idFrom = 0;
1547  sc.nmhdr.code = EN_SELCHANGE;
1548  ME_GetSelectionOfs(editor, &sc.chrg.cpMin, &sc.chrg.cpMax);
1549  sc.seltyp = SEL_EMPTY;
1550  if (sc.chrg.cpMin != sc.chrg.cpMax)
1551  sc.seltyp |= SEL_TEXT;
1552  if (sc.chrg.cpMin < sc.chrg.cpMax+1) /* what were RICHEDIT authors thinking ? */
1553  sc.seltyp |= SEL_MULTICHAR;
1554 
1555  if (sc.chrg.cpMin != editor->notified_cr.cpMin || sc.chrg.cpMax != editor->notified_cr.cpMax)
1556  {
1557  ME_ClearTempStyle(editor);
1558 
1559  editor->notified_cr = sc.chrg;
1560 
1561  if (editor->nEventMask & ENM_SELCHANGE)
1562  {
1563  TRACE("cpMin=%d cpMax=%d seltyp=%d (%s %s)\n",
1564  sc.chrg.cpMin, sc.chrg.cpMax, sc.seltyp,
1565  (sc.seltyp & SEL_TEXT) ? "SEL_TEXT" : "",
1566  (sc.seltyp & SEL_MULTICHAR) ? "SEL_MULTICHAR" : "");
1567  ITextHost_TxNotify(editor->texthost, sc.nmhdr.code, &sc);
1568  }
1569  }
1570 }
1571 
1572 BOOL
1573 ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend, BOOL ctrl)
1574 {
1575  int nCursor = 0;
1576  ME_Cursor *p = &editor->pCursors[nCursor];
1577  ME_Cursor tmp_curs = *p;
1578  BOOL success = FALSE;
1579 
1580  ME_CheckCharOffsets(editor);
1581  switch(nVKey) {
1582  case VK_LEFT:
1583  editor->bCaretAtEnd = FALSE;
1584  if (ctrl)
1585  success = ME_MoveCursorWords(editor, &tmp_curs, -1);
1586  else
1587  success = ME_MoveCursorChars(editor, &tmp_curs, -1, extend);
1588  break;
1589  case VK_RIGHT:
1590  editor->bCaretAtEnd = FALSE;
1591  if (ctrl)
1592  success = ME_MoveCursorWords(editor, &tmp_curs, +1);
1593  else
1594  success = ME_MoveCursorChars(editor, &tmp_curs, +1, extend);
1595  break;
1596  case VK_UP:
1597  ME_MoveCursorLines(editor, &tmp_curs, -1, extend);
1598  break;
1599  case VK_DOWN:
1600  ME_MoveCursorLines(editor, &tmp_curs, +1, extend);
1601  break;
1602  case VK_PRIOR:
1603  ME_ArrowPageUp(editor, &tmp_curs);
1604  break;
1605  case VK_NEXT:
1606  ME_ArrowPageDown(editor, &tmp_curs);
1607  break;
1608  case VK_HOME: {
1609  if (ctrl)
1610  ME_ArrowCtrlHome(editor, &tmp_curs);
1611  else
1612  ME_ArrowHome(editor, &tmp_curs);
1613  editor->bCaretAtEnd = FALSE;
1614  break;
1615  }
1616  case VK_END:
1617  if (ctrl)
1618  ME_ArrowCtrlEnd(editor, &tmp_curs);
1619  else
1620  ME_ArrowEnd(editor, &tmp_curs);
1621  break;
1622  }
1623 
1624  if (!extend)
1625  editor->pCursors[1] = tmp_curs;
1626  *p = tmp_curs;
1627 
1628  ME_InvalidateSelection(editor);
1629  ME_Repaint(editor);
1631  ME_EnsureVisible(editor, &tmp_curs);
1632  ME_ShowCaret(editor);
1633  ME_SendSelChange(editor);
1634  return success;
1635 }
ME_DIType type
Definition: editstr.h:260
ME_DisplayItem * ME_GetTableRowStart(ME_DisplayItem *para) DECLSPEC_HIDDEN
Definition: table.c:154
#define MEPF_ROWEND
Definition: editstr.h:149
void ME_SetDefaultParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt) DECLSPEC_HIDDEN
Definition: para.c:993
ME_DIType
Definition: editstr.h:86
void ME_InvalidateSelection(ME_TextEditor *editor) DECLSPEC_HIDDEN
Definition: paint.c:1327
BOOL WINAPI GetCPInfo(UINT CodePage, LPCPINFO CodePageInfo)
Definition: nls.c:1904
GLint GLint GLsizei width
Definition: gl.h:1546
static void ME_ArrowCtrlEnd(ME_TextEditor *editor, ME_Cursor *pCursor)
Definition: caret.c:1515
#define WB_ISDELIMITER
Definition: winuser.h:549
ME_Paragraph para
Definition: editstr.h:266
void ME_CheckCharOffsets(ME_TextEditor *editor) DECLSPEC_HIDDEN
Definition: run.c:101
#define TRUE
Definition: types.h:120
WORD seltyp
Definition: richedit.h:687
#define shift
Definition: input.c:1668
ME_Style * ME_GetInsertStyle(ME_TextEditor *editor, int nCursor) DECLSPEC_HIDDEN
Definition: style.c:457
#define swap(a, b)
Definition: qsort.c:63
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
void ME_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCursor) DECLSPEC_HIDDEN
Definition: run.c:171
long y
Definition: polytest.cpp:48
REOBJECT obj
Definition: editstr.h:159
DWORD styleFlags
Definition: editstr.h:392
RECO_DRAG struct _reobject REOBJECT
long x
Definition: polytest.cpp:48
void ME_ScrollDown(ME_TextEditor *editor, int cy) DECLSPEC_HIDDEN
Definition: paint.c:1131
static void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
Definition: caret.c:1464
#define pt(x, y)
Definition: drawing.c:79
#define ITextHost_TxCreateCaret(This, a, b, c)
Definition: editor.h:296
union tagME_DisplayItem::@503 member
__WINE_SERVER_LIST_INLINE void list_add_after(struct list *elem, struct list *to_add)
Definition: list.h:78
struct re_object * reobj
Definition: editstr.h:172
#define ENM_SELCHANGE
Definition: richedit.h:478
#define WARN(fmt,...)
Definition: debug.h:111
struct tagME_DisplayItem * pCell
Definition: editstr.h:211
#define ES_MULTILINE
Definition: pedump.c:667
#define MERF_GRAPHICS
Definition: editstr.h:109
int ME_CallWordBreakProc(ME_TextEditor *editor, WCHAR *str, INT len, INT start, INT code) DECLSPEC_HIDDEN
Definition: string.c:192
__WINE_SERVER_LIST_INLINE void list_add_head(struct list *list, struct list *elem)
Definition: list.h:96
void ME_ScrollUp(ME_TextEditor *editor, int cy) DECLSPEC_HIDDEN
Definition: paint.c:1126
void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, const WCHAR *str, int len, ME_Style *style)
Definition: caret.c:536
void ME_StrDeleteV(ME_String *s, int nVChar, int nChars) DECLSPEC_HIDDEN
Definition: string.c:147
struct tagME_Paragraph * para
Definition: editstr.h:165
LONG top
Definition: windef.h:292
ME_Style * ME_GetSelectionInsertStyle(ME_TextEditor *editor)
Definition: caret.c:1536
#define EN_SELCHANGE
Definition: richedit.h:193
CHARRANGE notified_cr
Definition: editstr.h:440
#define VK_LEFT
Definition: winuser.h:2178
#define assert(x)
Definition: debug.h:53
LONG cpMax
Definition: richedit.h:501
struct list reobj_list
Definition: editstr.h:448
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
static int ME_GetXForArrow(ME_TextEditor *editor, ME_Cursor *pCursor)
Definition: caret.c:1241
ME_DisplayItem * ME_SplitRunSimple(ME_TextEditor *editor, ME_Cursor *cursor) DECLSPEC_HIDDEN
Definition: run.c:258
int ME_GetSelectionOfs(ME_TextEditor *editor, int *from, int *to)
Definition: caret.c:42
struct tagME_DisplayItem * prev_para
Definition: editstr.h:221
UINT MaxCharSize
Definition: winnls.h:578
void ME_ShowCaret(ME_TextEditor *ed)
Definition: caret.c:285
GLuint GLuint end
Definition: gl.h:1545
_In_ UINT64 _In_ UINT64 _In_ UINT64 _In_opt_ traverse_ptr * tp
Definition: btrfs.c:2645
#define VK_DOWN
Definition: winuser.h:2181
#define VK_PRIOR
Definition: winuser.h:2174
ME_DisplayItem * ME_GetTableRowEnd(ME_DisplayItem *para) DECLSPEC_HIDDEN
Definition: table.c:136
#define ITextHost_TxGetClientRect(This, a)
Definition: editor.h:309
void ME_CopyReObject(REOBJECT *dst, const REOBJECT *src, DWORD flags) DECLSPEC_HIDDEN
Definition: richole.c:5912
LONG left
Definition: windef.h:291
static void ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs, BOOL extend)
Definition: caret.c:1266
int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset, BOOL visual_order) DECLSPEC_HIDDEN
Definition: run.c:599
int nCharOfs
Definition: editstr.h:166
void ME_ClearTempStyle(ME_TextEditor *editor) DECLSPEC_HIDDEN
Definition: style.c:504
ME_Style * style
Definition: editstr.h:164
LONG right
Definition: windef.h:293
#define WB_MOVEWORDLEFT
Definition: richedit.h:1000
#define lstrlenW
Definition: compat.h:407
void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, ME_Cursor *c, int *nChars) DECLSPEC_HIDDEN
Definition: table.c:287
void ME_LButtonDown(ME_TextEditor *editor, int x, int y, int clickNum)
Definition: caret.c:1145
ME_DisplayItem * ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *rp, ME_Style *style, const WCHAR *eol_str, int eol_len, int paraFlags) DECLSPEC_HIDDEN
Definition: para.c:546
void ME_InsertEndRowFromCursor(ME_TextEditor *editor, int nCursor)
Definition: caret.c:521
#define ITextHost_TxNotify(This, a, b)
Definition: editor.h:323
static void * heap_alloc(size_t len)
Definition: appwiz.h:65
#define PFM_TABLEROWDELIMITER
Definition: richedit.h:868
#define VK_NEXT
Definition: winuser.h:2175
SCROLLINFO vert_si
Definition: editstr.h:443
#define MERF_TAB
Definition: editstr.h:111
UINT code
Definition: winuser.h:3112
int ME_SetSelection(ME_TextEditor *editor, int from, int to)
Definition: caret.c:126
static const char * debugstr_run(const ME_Run *run)
Definition: editor.h:47
ME_DisplayItem * pFirst
Definition: editstr.h:272
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 VK_HOME
Definition: winuser.h:2177
#define VK_UP
Definition: winuser.h:2179
unsigned int BOOL
Definition: ntddk_ex.h:94
UINT_PTR idFrom
Definition: winuser.h:3111
static struct re_object * create_re_object(const REOBJECT *reo)
Definition: caret.c:474
POINT pt
Definition: editstr.h:243
#define FIXME(fmt,...)
Definition: debug.h:110
void ME_DestroyDisplayItem(ME_DisplayItem *item) DECLSPEC_HIDDEN
Definition: list.c:160
#define pp
Definition: hlsl.yy.c:978
#define ITextHost_TxShowCaret(This, a)
Definition: editor.h:297
#define MERF_ENDPARA
Definition: editstr.h:126
ME_TextBuffer * pBuffer
Definition: editstr.h:390
#define VK_SHIFT
Definition: winuser.h:2156
#define E_INVALIDARG
Definition: ddrawi.h:101
const WCHAR * str
void ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor, int *x, int *y, int *height)
Definition: caret.c:218
int nDescent
Definition: editstr.h:170
smooth NULL
Definition: ftsmooth.c:416
void ME_Repaint(ME_TextEditor *editor) DECLSPEC_HIDDEN
Definition: paint.c:106
int ME_GetSelection(ME_TextEditor *editor, ME_Cursor **from, ME_Cursor **to)
Definition: caret.c:57
Definition: editstr.h:91
static void ME_ArrowEnd(ME_TextEditor *editor, ME_Cursor *pCursor)
Definition: caret.c:1490
static void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
Definition: caret.c:1406
BOOL bCaretAtEnd
Definition: editstr.h:403
int len
Definition: editstr.h:167
void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC)
Definition: context.c:23
void ME_SkipAndPropagateCharOffset(ME_DisplayItem *p, int shift) DECLSPEC_HIDDEN
Definition: run.c:46
int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run, BOOL closest, BOOL visual_order) DECLSPEC_HIDDEN
Definition: run.c:523
BOOL WINAPI DestroyCaret(VOID)
Definition: caret.c:35
DWORD dwMask
Definition: richedit.h:667
#define ITextHost_TxGetDC(This)
Definition: editor.h:288
#define ctrl
Definition: input.c:1669
BOOL ME_DeleteTextAtCursor(ME_TextEditor *editor, int nCursor, int nChars)
Definition: caret.c:451
void ME_PropagateCharOffset(ME_DisplayItem *p, int shift) DECLSPEC_HIDDEN
Definition: run.c:59
SHORT WINAPI GetKeyState(_In_ int)
void ME_SetCursorToStart(ME_TextEditor *editor, ME_Cursor *cursor)
Definition: caret.c:27
BOOL ME_PrevRun(ME_DisplayItem **para, ME_DisplayItem **run, BOOL all_para) DECLSPEC_HIDDEN
Definition: list.c:93
#define GTL_NUMBYTES
Definition: richedit.h:1059
ME_SelectionType nSelectionType
Definition: editstr.h:436
BOOL ME_MoveCursorWords(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
Definition: caret.c:740
void ME_MouseMove(ME_TextEditor *editor, int x, int y)
Definition: caret.c:1208
BOOL ME_InternalDeleteText(ME_TextEditor *editor, ME_Cursor *start, int nChars, BOOL bForce)
Definition: caret.c:301
#define TRACE(s)
Definition: solgame.cpp:4
int ME_GetTextLengthEx(ME_TextEditor *editor, const GETTEXTLENGTHEX *how)
Definition: caret.c:91
__wchar_t WCHAR
Definition: xmlstorage.h:180
BOOL ME_CharFromPos(ME_TextEditor *editor, int x, int y, ME_Cursor *cursor, BOOL *isExact)
Definition: caret.c:1063
void ME_SendSelChange(ME_TextEditor *editor)
Definition: caret.c:1541
void ME_HideCaret(ME_TextEditor *ed)
Definition: caret.c:292
static void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
Definition: caret.c:1352
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y, ME_Cursor *result, BOOL *is_eol, BOOL final_eop)
Definition: caret.c:996
#define GTL_CLOSE
Definition: richedit.h:1057
const GLubyte * c
Definition: glext.h:8905
void ME_ReleaseStyle(ME_Style *item) DECLSPEC_HIDDEN
Definition: style.c:443
void ME_DeleteSelection(ME_TextEditor *editor)
Definition: caret.c:1527
#define success(from, fromstr, to, tostr)
ME_DisplayItem * pPara
Definition: editstr.h:279
void ME_Remove(ME_DisplayItem *diWhere) DECLSPEC_HIDDEN
Definition: list.c:35
void ME_DestroyContext(ME_Context *c)
Definition: context.c:42
GLbitfield flags
Definition: glext.h:7161
int nFlags
Definition: editstr.h:169
ME_DisplayItem * ME_GetParagraph(ME_DisplayItem *run) DECLSPEC_HIDDEN
Definition: para.c:816
static void ME_SetCursorToEnd(ME_TextEditor *editor, ME_Cursor *cursor, BOOL final_eop)
Definition: caret.c:34
#define MEPF_ROWSTART
Definition: editstr.h:148
#define MEPF_REWRAP
Definition: editstr.h:145
static __inline int is_eol(struct parser *parser, const CHAR *ptr)
Definition: inffile.c:440
ITextHost * texthost
Definition: editstr.h:387
#define SEL_MULTICHAR
Definition: richedit.h:825
int nWidth
Definition: editstr.h:168
int nOffset
Definition: editstr.h:281
#define PFE_TABLEROWDELIMITER
Definition: richedit.h:942
ME_SelectionType
Definition: editstr.h:360
GLenum GLsizei len
Definition: glext.h:6722
Definition: editstr.h:90
static WCHAR * get_text(const ME_Run *run, int offset)
Definition: editor.h:42
ME_DisplayItem * pLast
Definition: editstr.h:272
static ME_DisplayItem * ME_InternalInsertTextFromCursor(ME_TextEditor *editor, int nCursor, const WCHAR *str, int len, ME_Style *style, int flags)
Definition: caret.c:461
POINT pt
Definition: editstr.h:171
HWND hwndFrom
Definition: winuser.h:3110
ME_Cell cell
Definition: editstr.h:265
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
#define VK_RIGHT
Definition: winuser.h:2180
int ME_GetCursorOfs(const ME_Cursor *cursor)
Definition: caret.c:898
WORD wEffects
Definition: richedit.h:669
#define ERR(fmt,...)
Definition: debug.h:109
#define ITextHost_TxSetCaretPos(This, a, b)
Definition: editor.h:298
void ME_InsertOLEFromCursor(ME_TextEditor *editor, const REOBJECT *reo, int nCursor)
Definition: caret.c:487
NMHDR nmhdr
Definition: richedit.h:685
const char cursor[]
Definition: icontest.c:13
BOOL bEmulateVersion10
Definition: editstr.h:389
#define GTL_NUMCHARS
Definition: richedit.h:1058
ME_Cursor * pCursors
Definition: editstr.h:391
PARAFORMAT2 fmt
Definition: editstr.h:208
GLuint start
Definition: gl.h:1545
#define MERF_ENDROW
Definition: editstr.h:128
SCROLLINFO horz_si
Definition: editstr.h:443
#define SEL_EMPTY
Definition: richedit.h:822
ME_DisplayItem * ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp, BOOL keepFirstParaFormat) DECLSPEC_HIDDEN
Definition: para.c:688
CHARRANGE chrg
Definition: richedit.h:686
#define min(a, b)
Definition: monoChain.cc:55
struct tagME_DisplayItem * next_para
Definition: editstr.h:221
void ME_EnsureVisible(ME_TextEditor *editor, ME_Cursor *pCursor) DECLSPEC_HIDDEN
Definition: paint.c:1285
ME_DisplayItem * pRun
Definition: editstr.h:280
int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs, BOOL final_eop)
Definition: caret.c:661
#define WB_MOVEWORDRIGHT
Definition: richedit.h:1002
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
BOOL ME_IsSelection(ME_TextEditor *editor)
Definition: caret.c:1521
BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend, BOOL ctrl)
Definition: caret.c:1573
static void ME_ExtendAnchorSelection(ME_TextEditor *editor)
Definition: caret.c:1093
struct tagME_DisplayItem * next_cell
Definition: editstr.h:233
static ME_DisplayItem * ME_FindPixelPosInTableRow(int x, int y, ME_DisplayItem *para)
Definition: caret.c:905
#define c
Definition: ke_i.h:80
ME_DisplayItem * ME_FindItemFwd(ME_DisplayItem *di, ME_DIType nTypeOrClass) DECLSPEC_HIDDEN
Definition: list.c:134
LONG bottom
Definition: windef.h:294
int ME_PointFromCharContext(ME_Context *c, ME_Run *pRun, int nOffset, BOOL visual_order) DECLSPEC_HIDDEN
Definition: run.c:558
#define GTL_PRECISE
Definition: richedit.h:1056
static void ME_ArrowCtrlHome(ME_TextEditor *editor, ME_Cursor *pCursor)
Definition: caret.c:1484
ME_DisplayItem * ME_InsertRunAtCursor(ME_TextEditor *editor, ME_Cursor *cursor, ME_Style *style, const WCHAR *str, int len, int flags) DECLSPEC_HIDDEN
Definition: run.c:325
GLfloat GLfloat p
Definition: glext.h:8902
void mark_para_rewrap(ME_TextEditor *editor, ME_DisplayItem *para) DECLSPEC_HIDDEN
Definition: para.c:26
CardRegion * from
Definition: spigame.cpp:19
#define SEL_TEXT
Definition: richedit.h:823
#define GTL_USECRLF
Definition: richedit.h:1055
Arabic default style
Definition: afstyles.h:93
GLuint64EXT * result
Definition: glext.h:11304
EXTENT_DATA * ed
Definition: write.c:2826
LONG cy
Definition: windef.h:320
#define VK_END
Definition: winuser.h:2176
int nAscent
Definition: editstr.h:170
void ME_MoveCaret(ME_TextEditor *editor)
Definition: caret.c:271
static BOOL ME_FindRunInRow(ME_TextEditor *editor, ME_DisplayItem *pRow, int x, ME_Cursor *cursor, BOOL *pbCaretAtEnd)
Definition: caret.c:943
LONG cpMin
Definition: richedit.h:500
static void ME_SelectByType(ME_TextEditor *editor, ME_SelectionType selectionType)
Definition: caret.c:840
int ME_GetTextLength(ME_TextEditor *editor)
Definition: caret.c:83
struct list entry
Definition: editstr.h:158
ME_DisplayItem * ME_FindItemBack(ME_DisplayItem *di, ME_DIType nTypeOrClass) DECLSPEC_HIDDEN
Definition: list.c:111
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
WINE_DEFAULT_DEBUG_CHANNEL(richedit)
BOOL add_undo_insert_run(ME_TextEditor *, int pos, const WCHAR *str, int len, int flags, ME_Style *style) DECLSPEC_HIDDEN
Definition: undo.c:131
struct tagME_DisplayItem * prev_cell
Definition: editstr.h:233