ReactOS  0.4.14-dev-554-g2f8d847
table.c
Go to the documentation of this file.
1 /*
2  * RichEdit functions dealing with on tables
3  *
4  * Copyright 2008 by Dylan Smith
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 /*
22  * The implementation of tables differs greatly between version 3.0
23  * (in riched20.dll) and version 4.1 (in msftedit.dll) of richedit controls.
24  * Currently Wine is not distinguishing between version 3.0 and version 4.1,
25  * so v4.1 is assumed unless v1.0 is being emulated (i.e. riched32.dll is used).
26  * If this lack of distinction causes a bug in a Windows application, then Wine
27  * will need to start making this distinction.
28  *
29  * Richedit version 1.0 - 3.0:
30  * Tables are implemented in these versions using tabs at the end of cells,
31  * and tab stops to position the cells. The paragraph format flag PFE_TABLE
32  * will indicate that the paragraph is a table row. Note that in this
33  * implementation there is one paragraph per table row.
34  *
35  * Richedit version 4.1:
36  * Tables are implemented such that cells can contain multiple paragraphs,
37  * each with its own paragraph format, and cells may even contain tables
38  * nested within the cell.
39  *
40  * There is also a paragraph at the start of each table row that contains
41  * the rows paragraph format (e.g. to change the row alignment to row), and a
42  * paragraph at the end of the table row with the PFE_TABLEROWDELIMITER flag
43  * set. The paragraphs at the start and end of the table row should always be
44  * empty, but should have a length of 2.
45  *
46  * Wine implements this using display items (ME_DisplayItem) with a type of
47  * diCell. These cell display items store the cell properties, and are
48  * inserted into the editors linked list before each cell, and at the end of
49  * the last cell. The cell display item for a cell comes before the paragraphs
50  * for the cell, but the last cell display item refers to no cell, so it is
51  * just a delimiter.
52  */
53 
54 #include "editor.h"
55 #include "rtf.h"
56 
57 WINE_DEFAULT_DEBUG_CHANNEL(richedit_lists);
58 
59 static const WCHAR cr_lf[] = {'\r', '\n', 0};
60 
62  int nCursor,
63  const WCHAR *eol_str, int eol_len,
64  int paraFlags)
65 {
66  ME_Style *pStyle = ME_GetInsertStyle(editor, nCursor);
68  ME_Cursor* cursor = &editor->pCursors[nCursor];
69  if (cursor->nOffset)
70  ME_SplitRunSimple(editor, cursor);
71 
72  tp = ME_SplitParagraph(editor, cursor->pRun, pStyle, eol_str, eol_len, paraFlags);
73  ME_ReleaseStyle(pStyle);
74  cursor->pPara = tp;
75  cursor->pRun = ME_FindItemFwd(tp, diRun);
76  return tp;
77 }
78 
80 {
81  ME_DisplayItem *para;
82  para = ME_InsertEndParaFromCursor(editor, 0, cr_lf, 2, MEPF_ROWSTART);
83  return para->member.para.prev_para;
84 }
85 
87  ME_DisplayItem *para)
88 {
89  ME_DisplayItem *prev_para, *end_para;
90  ME_Cursor savedCursor = editor->pCursors[0];
91  ME_DisplayItem *startRowPara;
92  editor->pCursors[0].pPara = para;
93  editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun);
94  editor->pCursors[0].nOffset = 0;
95  editor->pCursors[1] = editor->pCursors[0];
96  startRowPara = ME_InsertTableRowStartFromCursor(editor);
97  savedCursor.pPara = ME_GetParagraph(savedCursor.pRun);
98  editor->pCursors[0] = savedCursor;
99  editor->pCursors[1] = editor->pCursors[0];
100 
101  end_para = editor->pCursors[0].pPara->member.para.next_para;
102  prev_para = startRowPara->member.para.next_para;
103  para = prev_para->member.para.next_para;
104  while (para != end_para)
105  {
106  para->member.para.pCell = prev_para->member.para.pCell;
107  para->member.para.nFlags |= MEPF_CELL;
110  para->member.para.fmt.wEffects |= PFE_TABLE;
112  prev_para = para;
113  para = para->member.para.next_para;
114  }
115  return startRowPara;
116 }
117 
118 /* Inserts a diCell and starts a new paragraph for the next cell.
119  *
120  * Returns the first paragraph of the new cell. */
122 {
123  ME_DisplayItem *para;
124  WCHAR tab = '\t';
125  para = ME_InsertEndParaFromCursor(editor, 0, &tab, 1, MEPF_CELL);
126  return para;
127 }
128 
130 {
131  ME_DisplayItem *para;
132  para = ME_InsertEndParaFromCursor(editor, 0, cr_lf, 2, MEPF_ROWEND);
133  return para->member.para.prev_para;
134 }
135 
137 {
138  ME_DisplayItem *cell;
139  assert(para);
140  if (para->member.para.nFlags & MEPF_ROWEND)
141  return para;
142  if (para->member.para.nFlags & MEPF_ROWSTART)
143  para = para->member.para.next_para;
144  cell = para->member.para.pCell;
145  assert(cell && cell->type == diCell);
146  while (cell->member.cell.next_cell)
147  cell = cell->member.cell.next_cell;
148 
149  para = ME_FindItemFwd(cell, diParagraph);
150  assert(para && para->member.para.nFlags & MEPF_ROWEND);
151  return para;
152 }
153 
155 {
156  ME_DisplayItem *cell;
157  assert(para);
158  if (para->member.para.nFlags & MEPF_ROWSTART)
159  return para;
160  if (para->member.para.nFlags & MEPF_ROWEND)
161  para = para->member.para.prev_para;
162  cell = para->member.para.pCell;
163  assert(cell && cell->type == diCell);
164  while (cell->member.cell.prev_cell)
165  cell = cell->member.cell.prev_cell;
166 
167  para = ME_FindItemBack(cell, diParagraph);
168  assert(para && para->member.para.nFlags & MEPF_ROWSTART);
169  return para;
170 }
171 
173 {
174  if (para->member.para.nFlags & MEPF_ROWEND)
175  para = para->member.para.prev_para;
176  while (para->member.para.pCell)
177  {
178  para = ME_GetTableRowStart(para);
179  if (!para->member.para.pCell)
180  break;
182  }
183  return para;
184 }
185 
186 /* Make a bunch of assertions to make sure tables haven't been corrupted.
187  *
188  * These invariants may not hold true in the middle of streaming in rich text
189  * or during an undo and redo of streaming in rich text. It should be safe to
190  * call this method after an event is processed.
191  */
193 {
194  if(TRACE_ON(richedit_lists))
195  {
196  TRACE("---\n");
197  ME_DumpDocument(editor->pBuffer);
198  }
199 #ifndef NDEBUG
200  {
201  ME_DisplayItem *p, *pPrev;
202  pPrev = editor->pBuffer->pFirst;
203  p = pPrev->next;
204  if (!editor->bEmulateVersion10) /* v4.1 */
205  {
206  while (p->type == diParagraph)
207  {
208  assert(p->member.para.fmt.dwMask & PFM_TABLE);
209  assert(p->member.para.fmt.dwMask & PFM_TABLEROWDELIMITER);
210  if (p->member.para.pCell)
211  {
212  assert(p->member.para.nFlags & MEPF_CELL);
213  assert(p->member.para.fmt.wEffects & PFE_TABLE);
214  }
215  if (p->member.para.pCell != pPrev->member.para.pCell)
216  {
217  /* There must be a diCell in between the paragraphs if pCell changes. */
219  assert(pCell);
221  }
222  if (p->member.para.nFlags & MEPF_ROWEND)
223  {
224  /* ROWEND must come after a cell. */
225  assert(pPrev->member.para.pCell);
226  assert(p->member.para.pCell
227  == pPrev->member.para.pCell->member.cell.parent_cell);
228  assert(p->member.para.fmt.wEffects & PFE_TABLEROWDELIMITER);
229  }
230  else if (p->member.para.pCell)
231  {
232  assert(!(p->member.para.fmt.wEffects & PFE_TABLEROWDELIMITER));
233  assert(pPrev->member.para.pCell ||
234  pPrev->member.para.nFlags & MEPF_ROWSTART);
235  if (pPrev->member.para.pCell &&
236  !(pPrev->member.para.nFlags & MEPF_ROWSTART))
237  {
238  assert(p->member.para.pCell->member.cell.parent_cell
239  == pPrev->member.para.pCell->member.cell.parent_cell);
240  if (pPrev->member.para.pCell != p->member.para.pCell)
241  assert(pPrev->member.para.pCell
242  == p->member.para.pCell->member.cell.prev_cell);
243  }
244  }
245  else if (!(p->member.para.nFlags & MEPF_ROWSTART))
246  {
247  assert(!(p->member.para.fmt.wEffects & PFE_TABLEROWDELIMITER));
248  /* ROWSTART must be followed by a cell. */
249  assert(!(p->member.para.nFlags & MEPF_CELL));
250  /* ROWSTART must be followed by a cell. */
251  assert(!(pPrev->member.para.nFlags & MEPF_ROWSTART));
252  }
253  pPrev = p;
254  p = p->member.para.next_para;
255  }
256  } else { /* v1.0 - 3.0 */
257  while (p->type == diParagraph)
258  {
259  assert(!(p->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND|MEPF_CELL)));
260  assert(p->member.para.fmt.dwMask & PFM_TABLE);
261  assert(!(p->member.para.fmt.wEffects & PFE_TABLEROWDELIMITER));
262  assert(!p->member.para.pCell);
263  p = p->member.para.next_para;
264  }
265  return;
266  }
267  assert(p->type == diTextEnd);
268  assert(!pPrev->member.para.pCell);
269  }
270 #endif
271 }
272 
274 {
275  PARAFORMAT2 *pFmt;
276  if (!pItem)
277  return FALSE;
278  if (pItem->type == diRun)
279  pItem = ME_GetParagraph(pItem);
280  if (pItem->type != diParagraph)
281  return FALSE;
282  pFmt = &pItem->member.para.fmt;
283  return pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE;
284 }
285 
286 /* Table rows should either be deleted completely or not at all. */
288 {
289  int nOfs = ME_GetCursorOfs(c);
290  ME_Cursor c2 = *c;
291  ME_DisplayItem *this_para = c->pPara;
292  ME_DisplayItem *end_para;
293 
294  ME_MoveCursorChars(editor, &c2, *nChars, FALSE);
295  end_para = c2.pPara;
296  if (c2.pRun->member.run.nFlags & MERF_ENDPARA) {
297  /* End offset might be in the middle of the end paragraph run.
298  * If this is the case, then we need to use the next paragraph as the last
299  * paragraphs.
300  */
301  int remaining = nOfs + *nChars - c2.pRun->member.run.nCharOfs
302  - end_para->member.para.nCharOfs;
303  if (remaining)
304  {
305  assert(remaining < c2.pRun->member.run.len);
306  end_para = end_para->member.para.next_para;
307  }
308  }
309  if (!editor->bEmulateVersion10) { /* v4.1 */
310  if (this_para->member.para.pCell != end_para->member.para.pCell ||
311  ((this_para->member.para.nFlags|end_para->member.para.nFlags)
313  {
314  while (this_para != end_para)
315  {
316  ME_DisplayItem *next_para = this_para->member.para.next_para;
317  BOOL bTruancateDeletion = FALSE;
318  if (this_para->member.para.nFlags & MEPF_ROWSTART) {
319  /* The following while loop assumes that next_para is MEPF_ROWSTART,
320  * so moving back one paragraph let's it be processed as the start
321  * of the row. */
322  next_para = this_para;
323  this_para = this_para->member.para.prev_para;
324  } else if (next_para->member.para.pCell != this_para->member.para.pCell
325  || this_para->member.para.nFlags & MEPF_ROWEND)
326  {
327  /* Start of the deletion from after the start of the table row. */
328  bTruancateDeletion = TRUE;
329  }
330  while (!bTruancateDeletion &&
331  next_para->member.para.nFlags & MEPF_ROWSTART)
332  {
333  next_para = ME_GetTableRowEnd(next_para)->member.para.next_para;
334  if (next_para->member.para.nCharOfs > nOfs + *nChars)
335  {
336  /* End of deletion is not past the end of the table row. */
337  next_para = this_para->member.para.next_para;
338  /* Delete the end paragraph preceding the table row if the
339  * preceding table row will be empty. */
340  if (this_para->member.para.nCharOfs >= nOfs)
341  {
342  next_para = next_para->member.para.next_para;
343  }
344  bTruancateDeletion = TRUE;
345  } else {
346  this_para = next_para->member.para.prev_para;
347  }
348  }
349  if (bTruancateDeletion)
350  {
351  ME_Run *end_run = &ME_FindItemBack(next_para, diRun)->member.run;
352  int nCharsNew = (next_para->member.para.nCharOfs - nOfs
353  - end_run->len);
354  nCharsNew = max(nCharsNew, 0);
355  assert(nCharsNew <= *nChars);
356  *nChars = nCharsNew;
357  break;
358  }
359  this_para = next_para;
360  }
361  }
362  } else { /* v1.0 - 3.0 */
363  ME_DisplayItem *pRun;
364  int nCharsToBoundary;
365 
366  if ((this_para->member.para.nCharOfs != nOfs || this_para == end_para) &&
367  this_para->member.para.fmt.dwMask & PFM_TABLE &&
368  this_para->member.para.fmt.wEffects & PFE_TABLE)
369  {
370  pRun = c->pRun;
371  /* Find the next tab or end paragraph to use as a delete boundary */
372  while (!(pRun->member.run.nFlags & (MERF_TAB|MERF_ENDPARA)))
373  pRun = ME_FindItemFwd(pRun, diRun);
374  nCharsToBoundary = pRun->member.run.nCharOfs
375  - c->pRun->member.run.nCharOfs
376  - c->nOffset;
377  *nChars = min(*nChars, nCharsToBoundary);
378  } else if (end_para->member.para.fmt.dwMask & PFM_TABLE &&
379  end_para->member.para.fmt.wEffects & PFE_TABLE)
380  {
381  /* The deletion starts from before the row, so don't join it with
382  * previous non-empty paragraphs. */
383  ME_DisplayItem *curPara;
384  pRun = NULL;
385  if (nOfs > this_para->member.para.nCharOfs) {
386  pRun = ME_FindItemBack(end_para, diRun);
387  curPara = end_para->member.para.prev_para;
388  }
389  if (!pRun) {
390  pRun = ME_FindItemFwd(end_para, diRun);
391  curPara = end_para;
392  }
393  if (pRun)
394  {
395  nCharsToBoundary = curPara->member.para.nCharOfs
396  + pRun->member.run.nCharOfs
397  - nOfs;
398  if (nCharsToBoundary >= 0)
399  *nChars = min(*nChars, nCharsToBoundary);
400  }
401  }
402  if (*nChars < 0)
403  *nChars = 0;
404  }
405 }
406 
408  ME_DisplayItem *table_row)
409 {
410  WCHAR endl = '\r', tab = '\t';
411  ME_DisplayItem *run;
412  PARAFORMAT2 *pFmt;
413  int i;
414 
415  assert(table_row);
416  assert(table_row->type == diParagraph);
417  if (!editor->bEmulateVersion10) { /* v4.1 */
418  ME_DisplayItem *insertedCell, *para, *cell, *prevTableEnd;
419  cell = ME_FindItemFwd(ME_GetTableRowStart(table_row), diCell);
420  prevTableEnd = ME_GetTableRowEnd(table_row);
421  para = prevTableEnd->member.para.next_para;
422  run = ME_FindItemFwd(para, diRun);
423  editor->pCursors[0].pPara = para;
424  editor->pCursors[0].pRun = run;
425  editor->pCursors[0].nOffset = 0;
426  editor->pCursors[1] = editor->pCursors[0];
427  para = ME_InsertTableRowStartFromCursor(editor);
428  insertedCell = ME_FindItemFwd(para, diCell);
429  /* Copy cell properties */
430  insertedCell->member.cell.nRightBoundary = cell->member.cell.nRightBoundary;
431  insertedCell->member.cell.border = cell->member.cell.border;
432  while (cell->member.cell.next_cell) {
433  cell = cell->member.cell.next_cell;
434  para = ME_InsertTableCellFromCursor(editor);
435  insertedCell = ME_FindItemBack(para, diCell);
436  /* Copy cell properties */
437  insertedCell->member.cell.nRightBoundary = cell->member.cell.nRightBoundary;
438  insertedCell->member.cell.border = cell->member.cell.border;
439  };
440  para = ME_InsertTableRowEndFromCursor(editor);
441  para->member.para.fmt = prevTableEnd->member.para.fmt;
442  /* return the table row start for the inserted paragraph */
444  } else { /* v1.0 - 3.0 */
445  run = ME_FindItemBack(table_row->member.para.next_para, diRun);
446  pFmt = &table_row->member.para.fmt;
447  assert(pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE);
448  editor->pCursors[0].pPara = table_row;
449  editor->pCursors[0].pRun = run;
450  editor->pCursors[0].nOffset = 0;
451  editor->pCursors[1] = editor->pCursors[0];
452  ME_InsertTextFromCursor(editor, 0, &endl, 1, run->member.run.style);
453  run = editor->pCursors[0].pRun;
454  for (i = 0; i < pFmt->cTabCount; i++) {
455  ME_InsertTextFromCursor(editor, 0, &tab, 1, run->member.run.style);
456  }
457  return table_row->member.para.next_para;
458  }
459 }
460 
461 /* Selects the next table cell or appends a new table row if at end of table */
463  ME_DisplayItem *run)
464 {
465  ME_DisplayItem *para = ME_GetParagraph(run);
466  int i;
467 
468  assert(run && run->type == diRun);
469  assert(ME_IsInTable(run));
470  if (!editor->bEmulateVersion10) { /* v4.1 */
471  ME_DisplayItem *cell;
472  /* Get the initial cell */
473  if (para->member.para.nFlags & MEPF_ROWSTART) {
474  cell = para->member.para.next_para->member.para.pCell;
475  } else if (para->member.para.nFlags & MEPF_ROWEND) {
476  cell = para->member.para.prev_para->member.para.pCell;
477  } else {
478  cell = para->member.para.pCell;
479  }
480  assert(cell);
481  /* Get the next cell. */
482  if (cell->member.cell.next_cell &&
483  cell->member.cell.next_cell->member.cell.next_cell)
484  {
485  cell = cell->member.cell.next_cell;
486  } else {
488  para = para->member.para.next_para;
489  assert(para);
490  if (para->member.para.nFlags & MEPF_ROWSTART) {
491  cell = para->member.para.next_para->member.para.pCell;
492  } else {
493  /* Insert row */
494  para = para->member.para.prev_para;
495  para = ME_AppendTableRow(editor, ME_GetTableRowStart(para));
496  /* Put cursor at the start of the new table row */
497  para = para->member.para.next_para;
498  editor->pCursors[0].pPara = para;
499  editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun);
500  editor->pCursors[0].nOffset = 0;
501  editor->pCursors[1] = editor->pCursors[0];
502  ME_WrapMarkedParagraphs(editor);
503  return;
504  }
505  }
506  /* Select cell */
507  editor->pCursors[1].pRun = ME_FindItemFwd(cell, diRun);
508  editor->pCursors[1].pPara = ME_GetParagraph(editor->pCursors[1].pRun);
509  editor->pCursors[1].nOffset = 0;
510  assert(editor->pCursors[0].pRun);
511  cell = cell->member.cell.next_cell;
512  editor->pCursors[0].pRun = ME_FindItemBack(cell, diRun);
513  editor->pCursors[0].pPara = ME_GetParagraph(editor->pCursors[0].pRun);
514  editor->pCursors[0].nOffset = 0;
515  assert(editor->pCursors[1].pRun);
516  } else { /* v1.0 - 3.0 */
517  if (run->member.run.nFlags & MERF_ENDPARA &&
519  {
520  run = ME_FindItemFwd(run, diRun);
521  assert(run);
522  }
523  for (i = 0; i < 2; i++)
524  {
525  while (!(run->member.run.nFlags & MERF_TAB))
526  {
528  if (run->type != diRun)
529  {
530  para = run;
531  if (ME_IsInTable(para))
532  {
533  run = ME_FindItemFwd(para, diRun);
534  assert(run);
535  editor->pCursors[0].pPara = para;
536  editor->pCursors[0].pRun = run;
537  editor->pCursors[0].nOffset = 0;
538  i = 1;
539  } else {
540  /* Insert table row */
541  para = ME_AppendTableRow(editor, para->member.para.prev_para);
542  /* Put cursor at the start of the new table row */
543  editor->pCursors[0].pPara = para;
544  editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun);
545  editor->pCursors[0].nOffset = 0;
546  editor->pCursors[1] = editor->pCursors[0];
547  ME_WrapMarkedParagraphs(editor);
548  return;
549  }
550  }
551  }
552  if (i == 0)
553  run = ME_FindItemFwd(run, diRun);
554  editor->pCursors[i].pRun = run;
555  editor->pCursors[i].pPara = ME_GetParagraph(run);
556  editor->pCursors[i].nOffset = 0;
557  }
558  }
559 }
560 
561 
562 void ME_TabPressedInTable(ME_TextEditor *editor, BOOL bSelectedRow)
563 {
564  /* FIXME: Shift tab should move to the previous cell. */
565  ME_Cursor fromCursor, toCursor;
566  ME_InvalidateSelection(editor);
567  {
568  int from, to;
569  from = ME_GetCursorOfs(&editor->pCursors[0]);
570  to = ME_GetCursorOfs(&editor->pCursors[1]);
571  if (from <= to)
572  {
573  fromCursor = editor->pCursors[0];
574  toCursor = editor->pCursors[1];
575  } else {
576  fromCursor = editor->pCursors[1];
577  toCursor = editor->pCursors[0];
578  }
579  }
580  if (!editor->bEmulateVersion10) /* v4.1 */
581  {
582  if (!ME_IsInTable(toCursor.pRun))
583  {
584  editor->pCursors[0] = toCursor;
585  editor->pCursors[1] = toCursor;
586  } else {
587  ME_SelectOrInsertNextCell(editor, toCursor.pRun);
588  }
589  } else { /* v1.0 - 3.0 */
590  if (!ME_IsInTable(fromCursor.pRun)) {
591  editor->pCursors[0] = fromCursor;
592  editor->pCursors[1] = fromCursor;
593  /* FIXME: For some reason the caret is shown at the start of the
594  * previous paragraph in v1.0 to v3.0, and bCaretAtEnd only works
595  * within the paragraph for wrapped lines. */
596  if (ME_FindItemBack(fromCursor.pRun, diRun))
597  editor->bCaretAtEnd = TRUE;
598  } else if ((bSelectedRow || !ME_IsInTable(toCursor.pRun))) {
599  ME_SelectOrInsertNextCell(editor, fromCursor.pRun);
600  } else {
601  if (ME_IsSelection(editor) && !toCursor.nOffset)
602  {
603  ME_DisplayItem *run;
604  run = ME_FindItemBack(toCursor.pRun, diRunOrParagraphOrEnd);
605  if (run->type == diRun && run->member.run.nFlags & MERF_TAB)
606  ME_SelectOrInsertNextCell(editor, run);
607  else
608  ME_SelectOrInsertNextCell(editor, toCursor.pRun);
609  } else {
610  ME_SelectOrInsertNextCell(editor, toCursor.pRun);
611  }
612  }
613  }
614  ME_InvalidateSelection(editor);
615  ME_Repaint(editor);
616  update_caret(editor);
617  ME_SendSelChange(editor);
618 }
619 
620 /* Make sure the cursor is not in the hidden table row start paragraph
621  * without a selection. */
623 {
624  ME_DisplayItem *para = editor->pCursors[0].pPara;
625  if (para == editor->pCursors[1].pPara &&
626  para->member.para.nFlags & MEPF_ROWSTART) {
627  /* The cursors should not be at the hidden start row paragraph without
628  * a selection, so the cursor is moved into the first cell. */
629  para = para->member.para.next_para;
630  editor->pCursors[0].pPara = para;
631  editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun);
632  editor->pCursors[0].nOffset = 0;
633  editor->pCursors[1] = editor->pCursors[0];
634  }
635 }
636 
638 {
639  RTFTable *tableDef = heap_alloc_zero(sizeof(*tableDef));
640 
641  if (!editor->bEmulateVersion10) /* v4.1 */
642  tableDef->gapH = 10;
643  return tableDef;
644 }
645 
646 void ME_InitTableDef(ME_TextEditor *editor, struct RTFTable *tableDef)
647 {
648  ZeroMemory(tableDef->cells, sizeof(tableDef->cells));
649  ZeroMemory(tableDef->border, sizeof(tableDef->border));
650  tableDef->numCellsDefined = 0;
651  tableDef->leftEdge = 0;
652  if (!editor->bEmulateVersion10) /* v4.1 */
653  tableDef->gapH = 10;
654  else /* v1.0 - 3.0 */
655  tableDef->gapH = 0;
656 }
ME_DIType type
Definition: editstr.h:260
#define MEPF_ROWEND
Definition: editstr.h:149
void ME_CheckTablesForCorruption(ME_TextEditor *editor)
Definition: table.c:192
void ME_InvalidateSelection(ME_TextEditor *editor) DECLSPEC_HIDDEN
Definition: paint.c:1317
int leftEdge
Definition: rtf.h:1030
#define max(a, b)
Definition: svc.c:63
ME_Paragraph para
Definition: editstr.h:266
#define TRUE
Definition: types.h:120
ME_Style * ME_GetInsertStyle(ME_TextEditor *editor, int nCursor) DECLSPEC_HIDDEN
Definition: style.c:476
ME_DisplayItem * ME_InsertTableCellFromCursor(ME_TextEditor *editor)
Definition: table.c:121
ME_DisplayItem * ME_GetTableRowStart(ME_DisplayItem *para)
Definition: table.c:154
void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, ME_Cursor *c, int *nChars)
Definition: table.c:287
struct tagME_DisplayItem * pCell
Definition: editstr.h:211
void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, const WCHAR *str, int len, ME_Style *style)
Definition: caret.c:550
#define assert(x)
Definition: debug.h:53
#define ZeroMemory
Definition: winbase.h:1642
ME_DisplayItem * ME_SplitRunSimple(ME_TextEditor *editor, ME_Cursor *cursor) DECLSPEC_HIDDEN
Definition: run.c:258
void ME_DumpDocument(ME_TextBuffer *buffer) DECLSPEC_HIDDEN
Definition: list.c:187
struct tagME_DisplayItem * prev_para
Definition: editstr.h:221
SHORT cTabCount
Definition: richedit.h:674
int nCharOfs
Definition: editstr.h:166
ME_Style * style
Definition: editstr.h:164
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
int numCellsDefined
Definition: rtf.h:1028
#define PFM_TABLEROWDELIMITER
Definition: richedit.h:868
RTFCell cells[MAX_TABLE_CELLS]
Definition: rtf.h:1027
#define MERF_TAB
Definition: editstr.h:111
int gapH
Definition: rtf.h:1030
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
basic_ostream< _CharT, _Traits > &_STLP_CALL endl(basic_ostream< _CharT, _Traits > &__os)
Definition: _ostream.h:357
struct tagME_DisplayItem * next
Definition: editstr.h:261
unsigned int BOOL
Definition: ntddk_ex.h:94
ME_DisplayItem * ME_InsertTableRowStartFromCursor(ME_TextEditor *editor)
Definition: table.c:79
ME_DisplayItem * ME_InsertTableRowStartAtParagraph(ME_TextEditor *editor, ME_DisplayItem *para)
Definition: table.c:86
#define MEPF_CELL
Definition: editstr.h:147
ME_DisplayItem * ME_InsertTableRowEndFromCursor(ME_TextEditor *editor)
Definition: table.c:129
RTFBorder border[6]
Definition: rtf.h:1032
static ME_DisplayItem * ME_InsertEndParaFromCursor(ME_TextEditor *editor, int nCursor, const WCHAR *eol_str, int eol_len, int paraFlags)
Definition: table.c:61
#define MERF_ENDPARA
Definition: editstr.h:126
ME_TextBuffer * pBuffer
Definition: editstr.h:390
smooth NULL
Definition: ftsmooth.c:416
void ME_Repaint(ME_TextEditor *editor) DECLSPEC_HIDDEN
Definition: paint.c:106
Definition: editstr.h:91
BOOL bCaretAtEnd
Definition: editstr.h:403
int len
Definition: editstr.h:167
#define PFE_TABLE
Definition: richedit.h:944
DWORD dwMask
Definition: richedit.h:667
_In_ uint64_t _In_ uint64_t _In_ uint64_t _In_opt_ traverse_ptr * tp
Definition: btrfs.c:2855
#define TRACE(s)
Definition: solgame.cpp:4
BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) DECLSPEC_HIDDEN
Definition: wrap.c:1093
__wchar_t WCHAR
Definition: xmlstorage.h:180
void ME_SendSelChange(ME_TextEditor *editor)
Definition: caret.c:1553
const GLubyte * c
Definition: glext.h:8905
void ME_ReleaseStyle(ME_Style *item) DECLSPEC_HIDDEN
Definition: style.c:462
ME_DisplayItem * pPara
Definition: editstr.h:279
int nFlags
Definition: editstr.h:169
ME_BorderRect border
Definition: editstr.h:229
ME_DisplayItem * ME_GetParagraph(ME_DisplayItem *run) DECLSPEC_HIDDEN
Definition: para.c:815
#define MEPF_ROWSTART
Definition: editstr.h:148
#define PFM_TABLE
Definition: richedit.h:870
int nRightBoundary
Definition: editstr.h:228
int nOffset
Definition: editstr.h:281
#define PFE_TABLEROWDELIMITER
Definition: richedit.h:942
Definition: editstr.h:90
ME_DisplayItem * ME_AppendTableRow(ME_TextEditor *editor, ME_DisplayItem *table_row)
Definition: table.c:407
ME_DisplayItem * ME_GetOuterParagraph(ME_DisplayItem *para)
Definition: table.c:172
ME_Cell cell
Definition: editstr.h:265
int ME_GetCursorOfs(const ME_Cursor *cursor)
Definition: caret.c:912
WORD wEffects
Definition: richedit.h:669
static void ME_SelectOrInsertNextCell(ME_TextEditor *editor, ME_DisplayItem *run)
Definition: table.c:462
const char cursor[]
Definition: icontest.c:13
BOOL bEmulateVersion10
Definition: editstr.h:389
ME_Cursor * pCursors
Definition: editstr.h:391
void ME_TabPressedInTable(ME_TextEditor *editor, BOOL bSelectedRow)
Definition: table.c:562
PARAFORMAT2 fmt
Definition: editstr.h:208
#define min(a, b)
Definition: monoChain.cc:55
struct tagME_DisplayItem * next_para
Definition: editstr.h:221
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
void ME_MoveCursorFromTableRowStartParagraph(ME_TextEditor *editor)
Definition: table.c:622
struct RTFTable * ME_MakeTableDef(ME_TextEditor *editor)
Definition: table.c:637
BOOL ME_IsSelection(ME_TextEditor *editor)
Definition: caret.c:1533
struct tagME_DisplayItem * next_cell
Definition: editstr.h:233
static const WCHAR cr_lf[]
Definition: table.c:59
Definition: rtf.h:1025
#define c
Definition: ke_i.h:80
ME_DisplayItem * ME_FindItemFwd(ME_DisplayItem *di, ME_DIType nTypeOrClass) DECLSPEC_HIDDEN
Definition: list.c:134
BOOL ME_IsInTable(ME_DisplayItem *pItem)
Definition: table.c:273
void update_caret(ME_TextEditor *editor)
Definition: caret.c:298
GLfloat GLfloat p
Definition: glext.h:8902
ME_DisplayItem * ME_GetTableRowEnd(ME_DisplayItem *para)
Definition: table.c:136
CardRegion * from
Definition: spigame.cpp:19
void ME_InitTableDef(ME_TextEditor *editor, struct RTFTable *tableDef)
Definition: table.c:646
#define TRACE_ON(x)
Definition: compat.h:65
WINE_DEFAULT_DEBUG_CHANNEL(msidb)
ME_DisplayItem * ME_FindItemBack(ME_DisplayItem *di, ME_DIType nTypeOrClass) DECLSPEC_HIDDEN
Definition: list.c:111
union tagME_DisplayItem::@521 member
struct tagME_DisplayItem * prev_cell
Definition: editstr.h:233