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