mirror of
https://github.com/reactos/wine.git
synced 2025-01-27 06:53:49 +00:00
richedit: Each cell can contain multiple paragraphs in msftedit.
This commit is contained in:
parent
bc61a637b9
commit
300db3765f
@ -215,7 +215,7 @@ ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
|
||||
|
||||
*height = pSizeRun->member.run.nAscent + pSizeRun->member.run.nDescent;
|
||||
*x = run->member.run.pt.x + sz.cx;
|
||||
*y = para->member.para.nYPos + row->member.row.nBaseline + run->member.run.pt.y - pSizeRun->member.run.nAscent - ME_GetYScrollPos(editor);
|
||||
*y = para->member.para.pt.y + row->member.row.nBaseline + run->member.run.pt.y - pSizeRun->member.run.nAscent - ME_GetYScrollPos(editor);
|
||||
ME_DestroyContext(&c, editor->hWnd);
|
||||
return;
|
||||
}
|
||||
@ -316,6 +316,28 @@ BOOL ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars,
|
||||
}
|
||||
keepFirstParaFormat = (totalChars == nChars && nChars <= eollen &&
|
||||
run->nCharOfs);
|
||||
if (!editor->bEmulateVersion10) /* v4.1 */
|
||||
{
|
||||
ME_DisplayItem *next_para = ME_FindItemFwd(c.pRun, diParagraphOrEnd);
|
||||
ME_DisplayItem *this_para = next_para->member.para.prev_para;
|
||||
|
||||
/* The end of paragraph before a table row is only deleted if there
|
||||
* is nothing else on the line before it. */
|
||||
if (this_para == start_para &&
|
||||
next_para->member.para.nFlags & MEPF_ROWSTART)
|
||||
{
|
||||
/* If the paragraph will be empty, then it should be deleted, however
|
||||
* it still might have text right now which would inherit the
|
||||
* MEPF_STARTROW property if we joined it right now.
|
||||
* Instead we will delete it after the preceding text is deleted. */
|
||||
if (nOfs > this_para->member.para.nCharOfs) {
|
||||
/* Skip this end of line. */
|
||||
nChars -= (eollen < nChars) ? eollen : nChars;
|
||||
continue;
|
||||
}
|
||||
keepFirstParaFormat = TRUE;
|
||||
}
|
||||
}
|
||||
ME_JoinParagraphs(editor, ME_GetParagraph(c.pRun), keepFirstParaFormat);
|
||||
/* ME_SkipAndPropagateCharOffset(p->pRun, shift); */
|
||||
ME_CheckCharOffsets(editor);
|
||||
@ -583,7 +605,7 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
|
||||
pos++;
|
||||
numCR = 1; numLF = 0;
|
||||
}
|
||||
tp = ME_SplitParagraph(editor, p->pRun, p->pRun->member.run.style, numCR, numLF);
|
||||
tp = ME_SplitParagraph(editor, p->pRun, p->pRun->member.run.style, numCR, numLF, 0);
|
||||
p->pRun = ME_FindItemFwd(tp, diRun);
|
||||
end_run = ME_FindItemBack(tp, diRun);
|
||||
ME_ReleaseStyle(end_run->member.run.style);
|
||||
@ -630,7 +652,8 @@ ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs)
|
||||
assert(pRun->type != diRun && pRun->type != diParagraph);
|
||||
return FALSE;
|
||||
}
|
||||
} while (RUN_IS_HIDDEN(&pRun->member.run));
|
||||
} while (RUN_IS_HIDDEN(&pRun->member.run) ||
|
||||
pRun->member.run.nFlags & MERF_HIDDEN);
|
||||
pCursor->pRun = pRun;
|
||||
if (pRun->member.run.nFlags & MERF_ENDPARA)
|
||||
pCursor->nOffset = 0;
|
||||
@ -656,7 +679,8 @@ ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs)
|
||||
}
|
||||
do {
|
||||
pRun = ME_FindItemFwd(pRun, diRun);
|
||||
} while (pRun && RUN_IS_HIDDEN(&pRun->member.run));
|
||||
} while (pRun && (RUN_IS_HIDDEN(&pRun->member.run) ||
|
||||
pRun->member.run.nFlags & MERF_HIDDEN));
|
||||
if (pRun)
|
||||
{
|
||||
pCursor->pRun = pRun;
|
||||
@ -701,9 +725,13 @@ ME_MoveCursorWords(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
|
||||
{
|
||||
if (cursor->pRun == pRun && cursor->nOffset == 0)
|
||||
{
|
||||
/* Skip empty start of table row paragraph */
|
||||
if (pOtherRun->member.para.prev_para->member.para.nFlags & MEPF_ROWSTART)
|
||||
pOtherRun = pOtherRun->member.para.prev_para;
|
||||
/* Paragraph breaks are treated as separate words */
|
||||
if (pOtherRun->member.para.prev_para->type == diTextStart)
|
||||
return FALSE;
|
||||
|
||||
pRun = ME_FindItemBack(pOtherRun, diRunOrParagraph);
|
||||
}
|
||||
break;
|
||||
@ -734,6 +762,8 @@ ME_MoveCursorWords(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
|
||||
}
|
||||
else if (pOtherRun->type == diParagraph)
|
||||
{
|
||||
if (pOtherRun->member.para.nFlags & MEPF_ROWSTART)
|
||||
pOtherRun = pOtherRun->member.para.next_para;
|
||||
if (cursor->pRun == pRun)
|
||||
pRun = ME_FindItemFwd(pOtherRun, diRun);
|
||||
nOffset = 0;
|
||||
@ -820,6 +850,45 @@ int ME_GetCursorOfs(ME_TextEditor *editor, int nCursor)
|
||||
+ pCursor->pRun->member.run.nCharOfs + pCursor->nOffset;
|
||||
}
|
||||
|
||||
/* Helper function for ME_FindPixelPos to find paragraph within tables */
|
||||
static ME_DisplayItem* ME_FindPixelPosInTableRow(int x, int y,
|
||||
ME_DisplayItem *para)
|
||||
{
|
||||
ME_DisplayItem *cell, *next_cell;
|
||||
assert(para->member.para.nFlags & MEPF_ROWSTART);
|
||||
cell = para->member.para.next_para->member.para.pCell;
|
||||
assert(cell);
|
||||
|
||||
/* find the cell we are in */
|
||||
while ((next_cell = cell->member.cell.next_cell) != NULL) {
|
||||
if (x < next_cell->member.cell.pt.x)
|
||||
{
|
||||
para = ME_FindItemFwd(cell, diParagraph);
|
||||
/* Found the cell, but there might be multiple paragraphs in
|
||||
* the cell, so need to search down the cell for the paragraph. */
|
||||
while (cell == para->member.para.pCell) {
|
||||
if (y < para->member.para.pt.y + para->member.para.nHeight)
|
||||
{
|
||||
if (para->member.para.nFlags & MEPF_ROWSTART)
|
||||
return ME_FindPixelPosInTableRow(x, y, para);
|
||||
else
|
||||
return para;
|
||||
}
|
||||
para = para->member.para.next_para;
|
||||
}
|
||||
/* Past the end of the cell, so go back to the last cell paragraph */
|
||||
return para->member.para.prev_para;
|
||||
}
|
||||
cell = next_cell;
|
||||
}
|
||||
/* Return table row delimiter */
|
||||
para = ME_FindItemFwd(cell, diParagraph);
|
||||
assert(para->member.para.nFlags & MEPF_ROWEND);
|
||||
assert(para->member.para.pFmt->dwMask & PFM_TABLEROWDELIMITER);
|
||||
assert(para->member.para.pFmt->wEffects & PFE_TABLEROWDELIMITER);
|
||||
return para;
|
||||
}
|
||||
|
||||
/* Finds the run and offset from the pixel position.
|
||||
*
|
||||
* x & y are pixel positions in virtual coordinates into the rich edit control,
|
||||
@ -843,11 +912,15 @@ static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y,
|
||||
for (; p != editor->pBuffer->pLast; p = p->member.para.next_para)
|
||||
{
|
||||
assert(p->type == diParagraph);
|
||||
if (y < p->member.para.nYPos + p->member.para.nHeight)
|
||||
if (y < p->member.para.pt.y + p->member.para.nHeight)
|
||||
{
|
||||
y -= p->member.para.nYPos;
|
||||
if (p->member.para.nFlags & MEPF_ROWSTART)
|
||||
p = ME_FindPixelPosInTableRow(x, y, p);
|
||||
y -= p->member.para.pt.y;
|
||||
p = ME_FindItemFwd(p, diStartRow);
|
||||
break;
|
||||
} else if (p->member.para.nFlags & MEPF_ROWSTART) {
|
||||
p = ME_GetTableRowEnd(p);
|
||||
}
|
||||
}
|
||||
/* find row */
|
||||
@ -855,7 +928,7 @@ static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y,
|
||||
{
|
||||
ME_DisplayItem *pp;
|
||||
assert(p->type == diStartRow);
|
||||
if (y < p->member.row.nYPos + p->member.row.nHeight)
|
||||
if (y < p->member.row.pt.y + p->member.row.nHeight)
|
||||
{
|
||||
p = ME_FindItemFwd(p, diRun);
|
||||
break;
|
||||
@ -911,6 +984,7 @@ static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y,
|
||||
if (is_eol) *is_eol = 1;
|
||||
rx = 0; /* FIXME not sure */
|
||||
goto found_here;
|
||||
case diCell:
|
||||
case diParagraph:
|
||||
case diTextEnd:
|
||||
isExact = FALSE;
|
||||
@ -1185,13 +1259,14 @@ static void
|
||||
ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs)
|
||||
{
|
||||
ME_DisplayItem *pRun = pCursor->pRun;
|
||||
ME_DisplayItem *pItem;
|
||||
ME_DisplayItem *pItem, *pOldPara, *pNewPara;
|
||||
int x = ME_GetXForArrow(editor, pCursor);
|
||||
|
||||
if (editor->bCaretAtEnd && !pCursor->nOffset)
|
||||
pRun = ME_FindItemBack(pRun, diRun);
|
||||
if (!pRun)
|
||||
return;
|
||||
pOldPara = ME_GetParagraph(pRun);
|
||||
if (nRelOfs == -1)
|
||||
{
|
||||
/* start of this row */
|
||||
@ -1199,13 +1274,57 @@ ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs)
|
||||
assert(pItem);
|
||||
/* start of the previous row */
|
||||
pItem = ME_FindItemBack(pItem, diStartRow);
|
||||
if (!pItem)
|
||||
return; /* row not found - ignore */
|
||||
pNewPara = ME_GetParagraph(pItem);
|
||||
if (pOldPara->member.para.nFlags & MEPF_ROWEND ||
|
||||
(pOldPara->member.para.pCell &&
|
||||
pOldPara->member.para.pCell != pNewPara->member.para.pCell))
|
||||
{
|
||||
/* Brought out of a cell */
|
||||
pNewPara = ME_GetTableRowStart(pOldPara)->member.para.prev_para;
|
||||
if (pNewPara->type == diTextStart)
|
||||
return; /* At the top, so don't go anywhere. */
|
||||
pItem = ME_FindItemFwd(pNewPara, diStartRow);
|
||||
}
|
||||
if (pNewPara->member.para.nFlags & MEPF_ROWEND)
|
||||
{
|
||||
/* Brought into a table row */
|
||||
ME_Cell *cell = &ME_FindItemBack(pNewPara, diCell)->member.cell;
|
||||
while (x < cell->pt.x && cell->prev_cell)
|
||||
cell = &cell->prev_cell->member.cell;
|
||||
if (cell->next_cell) /* else - we are still at the end of the row */
|
||||
pItem = ME_FindItemBack(cell->next_cell, diStartRow);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* start of the next row */
|
||||
pItem = ME_FindItemFwd(pRun, diStartRow);
|
||||
if (!pItem)
|
||||
return; /* row not found - ignore */
|
||||
/* FIXME If diParagraph is before diStartRow, wrap the next paragraph?
|
||||
*/
|
||||
pNewPara = ME_GetParagraph(pItem);
|
||||
if (pOldPara->member.para.nFlags & MEPF_ROWSTART ||
|
||||
(pOldPara->member.para.pCell &&
|
||||
pOldPara->member.para.pCell != pNewPara->member.para.pCell))
|
||||
{
|
||||
/* Brought out of a cell */
|
||||
pNewPara = ME_GetTableRowEnd(pOldPara)->member.para.next_para;
|
||||
if (pNewPara->type == diTextEnd)
|
||||
return; /* At the bottom, so don't go anywhere. */
|
||||
pItem = ME_FindItemFwd(pNewPara, diStartRow);
|
||||
}
|
||||
if (pNewPara->member.para.nFlags & MEPF_ROWSTART)
|
||||
{
|
||||
/* Brought into a table row */
|
||||
ME_DisplayItem *cell = ME_FindItemFwd(pNewPara, diCell);
|
||||
while (cell->member.cell.next_cell &&
|
||||
x >= cell->member.cell.next_cell->member.cell.pt.x)
|
||||
cell = cell->member.cell.next_cell;
|
||||
pItem = ME_FindItemFwd(cell, diStartRow);
|
||||
}
|
||||
}
|
||||
if (!pItem)
|
||||
{
|
||||
@ -1231,8 +1350,8 @@ static void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
|
||||
|
||||
p = ME_FindItemBack(pRun, diStartRowOrParagraph);
|
||||
assert(p->type == diStartRow);
|
||||
yp = ME_FindItemBack(p, diParagraph)->member.para.nYPos;
|
||||
yprev = ys = y = yp + p->member.row.nYPos;
|
||||
yp = ME_FindItemBack(p, diParagraph)->member.para.pt.y;
|
||||
yprev = ys = y = yp + p->member.row.pt.y;
|
||||
yd = y - editor->sizeWindow.cy;
|
||||
pLast = p;
|
||||
|
||||
@ -1243,10 +1362,10 @@ static void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
|
||||
if (p->type == diParagraph) { /* crossing paragraphs */
|
||||
if (p->member.para.prev_para == NULL)
|
||||
break;
|
||||
yp = p->member.para.prev_para->member.para.nYPos;
|
||||
yp = p->member.para.prev_para->member.para.pt.y;
|
||||
continue;
|
||||
}
|
||||
y = yp + p->member.row.nYPos;
|
||||
y = yp + p->member.row.pt.y;
|
||||
if (y < yd)
|
||||
break;
|
||||
pLast = p;
|
||||
@ -1286,8 +1405,8 @@ static void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
|
||||
|
||||
p = ME_FindItemBack(pRun, diStartRowOrParagraph);
|
||||
assert(p->type == diStartRow);
|
||||
yp = ME_FindItemBack(p, diParagraph)->member.para.nYPos;
|
||||
yprev = ys = y = yp + p->member.row.nYPos;
|
||||
yp = ME_FindItemBack(p, diParagraph)->member.para.pt.y;
|
||||
yprev = ys = y = yp + p->member.row.pt.y;
|
||||
yd = y + editor->sizeWindow.cy;
|
||||
pLast = p;
|
||||
|
||||
@ -1296,10 +1415,10 @@ static void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
|
||||
if (!p)
|
||||
break;
|
||||
if (p->type == diParagraph) {
|
||||
yp = p->member.para.nYPos;
|
||||
yp = p->member.para.pt.y;
|
||||
continue;
|
||||
}
|
||||
y = yp + p->member.row.nYPos;
|
||||
y = yp + p->member.row.pt.y;
|
||||
if (y >= yd)
|
||||
break;
|
||||
pLast = p;
|
||||
|
@ -451,8 +451,9 @@ static void ME_RTFParAttrHook(RTF_Info *info)
|
||||
switch(info->rtfMinor)
|
||||
{
|
||||
case rtfParDef: /* restores default paragraph attributes */
|
||||
fmt.dwMask = PFM_ALIGNMENT | PFM_BORDER | PFM_LINESPACING | PFM_TABSTOPS | PFM_OFFSET |
|
||||
PFM_RIGHTINDENT | PFM_SPACEAFTER | PFM_SPACEBEFORE | PFM_STARTINDENT | PFM_TABLE;
|
||||
fmt.dwMask = PFM_ALIGNMENT | PFM_BORDER | PFM_LINESPACING | PFM_TABSTOPS |
|
||||
PFM_OFFSET | PFM_RIGHTINDENT | PFM_SPACEAFTER | PFM_SPACEBEFORE |
|
||||
PFM_STARTINDENT;
|
||||
/* TODO: numbering, shading */
|
||||
fmt.wAlignment = PFA_LEFT;
|
||||
fmt.cTabCount = 0;
|
||||
@ -462,12 +463,67 @@ static void ME_RTFParAttrHook(RTF_Info *info)
|
||||
fmt.bLineSpacingRule = 0;
|
||||
fmt.dySpaceBefore = fmt.dySpaceAfter = 0;
|
||||
fmt.dyLineSpacing = 0;
|
||||
fmt.wEffects &= ~PFE_TABLE;
|
||||
if (!info->editor->bEmulateVersion10) /* v4.1 */
|
||||
{
|
||||
if (info->tableDef && info->tableDef->tableRowStart &&
|
||||
info->tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND)
|
||||
{
|
||||
ME_Cursor cursor;
|
||||
ME_DisplayItem *para;
|
||||
/* We are just after a table row. */
|
||||
RTFFlushOutputBuffer(info);
|
||||
cursor = info->editor->pCursors[0];
|
||||
para = ME_GetParagraph(cursor.pRun);
|
||||
if (para == info->tableDef->tableRowStart->member.para.next_para
|
||||
&& !cursor.nOffset && !cursor.pRun->member.run.nCharOfs)
|
||||
{
|
||||
/* Since the table row end, no text has been inserted, and the \intbl
|
||||
* control word has not be used. We can confirm that we are not in a
|
||||
* table anymore.
|
||||
*/
|
||||
info->tableDef->tableRowStart = NULL;
|
||||
}
|
||||
}
|
||||
} else { /* v1.0 - v3.0 */
|
||||
fmt.dwMask |= PFM_TABLE;
|
||||
fmt.wEffects &= ~PFE_TABLE;
|
||||
}
|
||||
break;
|
||||
case rtfInTable:
|
||||
{
|
||||
fmt.dwMask |= PFM_TABLE;
|
||||
fmt.wEffects |= PFE_TABLE;
|
||||
ME_Cursor cursor;
|
||||
if (!info->editor->bEmulateVersion10) /* v4.1 */
|
||||
{
|
||||
if (!info->tableDef || !info->tableDef->tableRowStart ||
|
||||
info->tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND)
|
||||
{
|
||||
RTFTable *tableDef;
|
||||
if (!info->tableDef)
|
||||
{
|
||||
info->tableDef = ALLOC_OBJ(RTFTable);
|
||||
ZeroMemory(info->tableDef, sizeof(RTFTable));
|
||||
}
|
||||
tableDef = info->tableDef;
|
||||
RTFFlushOutputBuffer(info);
|
||||
if (!tableDef->tableRowStart)
|
||||
{
|
||||
WCHAR endl = '\r';
|
||||
cursor = info->editor->pCursors[0];
|
||||
if (cursor.nOffset || cursor.pRun->member.run.nCharOfs)
|
||||
ME_InsertTextFromCursor(info->editor, 0, &endl, 1, info->style);
|
||||
}
|
||||
|
||||
/* FIXME: Remove the following condition once nested tables are supported */
|
||||
if (ME_GetParagraph(info->editor->pCursors[0].pRun)->member.para.pCell)
|
||||
break;
|
||||
|
||||
tableDef->tableRowStart = ME_InsertTableRowStartFromCursor(info->editor);
|
||||
}
|
||||
return;
|
||||
} else { /* v1.0 - v3.0 */
|
||||
fmt.dwMask |= PFM_TABLE;
|
||||
fmt.wEffects |= PFE_TABLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rtfFirstIndent:
|
||||
@ -669,10 +725,16 @@ static void ME_RTFTblAttrHook(RTF_Info *info)
|
||||
switch (info->rtfMinor)
|
||||
{
|
||||
case rtfRowDef:
|
||||
if (!info->tableDef)
|
||||
{
|
||||
if (!info->tableDef) {
|
||||
info->tableDef = ALLOC_OBJ(RTFTable);
|
||||
ZeroMemory(info->tableDef, sizeof(RTFTable));
|
||||
ZeroMemory(info->tableDef, sizeof(RTFTable));
|
||||
} else {
|
||||
ZeroMemory(info->tableDef->cells, sizeof(info->tableDef->cells));
|
||||
info->tableDef->numCellsDefined = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rtfCellPos:
|
||||
if (!info->tableDef)
|
||||
{
|
||||
@ -683,7 +745,8 @@ static void ME_RTFTblAttrHook(RTF_Info *info)
|
||||
break;
|
||||
info->tableDef->cells[info->tableDef->numCellsDefined].rightBoundary = info->rtfParam;
|
||||
{
|
||||
/* Tab stops store the cell positions. */
|
||||
/* Tab stops were used to store cell positions before v4.1 but v4.1
|
||||
* still seems to set the tabstops without using them. */
|
||||
ME_DisplayItem *para = ME_GetParagraph(info->editor->pCursors[0].pRun);
|
||||
PARAFORMAT2 *pFmt = para->member.para.pFmt;
|
||||
int cellNum = info->tableDef->numCellsDefined;
|
||||
@ -704,7 +767,19 @@ static void ME_RTFSpecialCharHook(RTF_Info *info)
|
||||
if (!tableDef)
|
||||
break;
|
||||
RTFFlushOutputBuffer(info);
|
||||
{
|
||||
if (!info->editor->bEmulateVersion10) { /* v4.1 */
|
||||
if (tableDef->tableRowStart)
|
||||
{
|
||||
if (tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND)
|
||||
{
|
||||
ME_DisplayItem *para = tableDef->tableRowStart;
|
||||
para = para->member.para.next_para;
|
||||
para = ME_InsertTableRowStartAtParagraph(info->editor, para);
|
||||
tableDef->tableRowStart = para;
|
||||
}
|
||||
ME_InsertTableCellFromCursor(info->editor);
|
||||
}
|
||||
} else { /* v1.0 - v3.0 */
|
||||
ME_DisplayItem *para = ME_GetParagraph(info->editor->pCursors[0].pRun);
|
||||
PARAFORMAT2 *pFmt = para->member.para.pFmt;
|
||||
if (pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE &&
|
||||
@ -718,11 +793,70 @@ static void ME_RTFSpecialCharHook(RTF_Info *info)
|
||||
break;
|
||||
case rtfRow:
|
||||
{
|
||||
ME_DisplayItem *para, *cell, *run;
|
||||
int i;
|
||||
|
||||
if (!tableDef)
|
||||
break;
|
||||
RTFFlushOutputBuffer(info);
|
||||
if (!info->editor->bEmulateVersion10) { /* v4.1 */
|
||||
if (!tableDef->tableRowStart)
|
||||
break;
|
||||
if (tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND)
|
||||
{
|
||||
para = tableDef->tableRowStart;
|
||||
para = para->member.para.next_para;
|
||||
para = ME_InsertTableRowStartAtParagraph(info->editor, para);
|
||||
tableDef->tableRowStart = para;
|
||||
}
|
||||
para = tableDef->tableRowStart;
|
||||
cell = ME_FindItemFwd(para, diCell);
|
||||
assert(cell && !cell->member.cell.prev_cell);
|
||||
if (tableDef->numCellsDefined < 1)
|
||||
{
|
||||
/* 2000 twips appears to be the cell size that native richedit uses
|
||||
* when no cell sizes are specified. */
|
||||
const int defaultCellSize = 2000;
|
||||
int nRightBoundary = defaultCellSize;
|
||||
cell->member.cell.nRightBoundary = nRightBoundary;
|
||||
while (cell->member.cell.next_cell) {
|
||||
cell = cell->member.cell.next_cell;
|
||||
nRightBoundary += defaultCellSize;
|
||||
cell->member.cell.nRightBoundary = nRightBoundary;
|
||||
}
|
||||
para = ME_InsertTableCellFromCursor(info->editor);
|
||||
cell = para->member.para.pCell;
|
||||
cell->member.cell.nRightBoundary = nRightBoundary;
|
||||
} else {
|
||||
for (i = 0; i < tableDef->numCellsDefined; i++)
|
||||
{
|
||||
cell->member.cell.nRightBoundary = tableDef->cells[i].rightBoundary;
|
||||
cell = cell->member.cell.next_cell;
|
||||
if (!cell)
|
||||
{
|
||||
para = ME_InsertTableCellFromCursor(info->editor);
|
||||
cell = para->member.para.pCell;
|
||||
}
|
||||
}
|
||||
/* Cell for table row delimiter is empty */
|
||||
cell->member.cell.nRightBoundary = tableDef->cells[i-1].rightBoundary;
|
||||
}
|
||||
|
||||
{
|
||||
run = ME_FindItemFwd(cell, diRun);
|
||||
if (info->editor->pCursors[0].pRun != run ||
|
||||
info->editor->pCursors[0].nOffset)
|
||||
{
|
||||
int nOfs, nChars;
|
||||
/* Delete inserted cells that aren't defined. */
|
||||
info->editor->pCursors[1].pRun = run;
|
||||
info->editor->pCursors[1].nOffset = 0;
|
||||
nOfs = ME_GetCursorOfs(info->editor, 1);
|
||||
nChars = ME_GetCursorOfs(info->editor, 0) - nOfs;
|
||||
ME_InternalDeleteText(info->editor, nOfs, nChars, TRUE);
|
||||
}
|
||||
|
||||
tableDef->tableRowStart = ME_InsertTableRowEndFromCursor(info->editor);
|
||||
} else { /* v1.0 - v3.0 */
|
||||
WCHAR endl = '\r';
|
||||
ME_DisplayItem *para = ME_GetParagraph(info->editor->pCursors[0].pRun);
|
||||
PARAFORMAT2 *pFmt = para->member.para.pFmt;
|
||||
@ -1128,6 +1262,8 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
|
||||
if (!invalidRTF && !inStream.editstream->dwError)
|
||||
{
|
||||
if (format & SF_RTF) {
|
||||
ME_DisplayItem *para;
|
||||
|
||||
/* setup the RTF parser */
|
||||
memset(&parser, 0, sizeof parser);
|
||||
RTFSetEditStream(&parser, &inStream);
|
||||
@ -1145,6 +1281,36 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
|
||||
/* do the parsing */
|
||||
RTFRead(&parser);
|
||||
RTFFlushOutputBuffer(&parser);
|
||||
if (!editor->bEmulateVersion10) { /* v4.1 */
|
||||
if (parser.tableDef && parser.tableDef->tableRowStart)
|
||||
{
|
||||
/* Delete any incomplete table row at the end of the rich text. */
|
||||
int nOfs, nChars;
|
||||
ME_DisplayItem *pCell;
|
||||
|
||||
para = parser.tableDef->tableRowStart;
|
||||
|
||||
parser.rtfMinor = rtfRow;
|
||||
/* Complete the table row before deleting it.
|
||||
* By doing it this way we will have the current paragraph format set
|
||||
* properly to reflect that is not in the complete table, and undo items
|
||||
* will be added for this change to the current paragraph format. */
|
||||
ME_RTFSpecialCharHook(&parser);
|
||||
if (para->member.para.nFlags & MEPF_ROWEND)
|
||||
{
|
||||
para = para->member.para.next_para;
|
||||
}
|
||||
pCell = para->member.para.pCell;
|
||||
|
||||
editor->pCursors[1].pRun = ME_FindItemFwd(para, diRun);
|
||||
editor->pCursors[1].nOffset = 0;
|
||||
nOfs = ME_GetCursorOfs(editor, 1);
|
||||
nChars = ME_GetCursorOfs(editor, 0) - nOfs;
|
||||
ME_InternalDeleteText(editor, nOfs, nChars, TRUE);
|
||||
parser.tableDef->tableRowStart = NULL;
|
||||
}
|
||||
}
|
||||
ME_CheckTablesForCorruption(editor);
|
||||
RTFDestroy(&parser);
|
||||
if (parser.lpRichEditOle)
|
||||
IRichEditOle_Release(parser.lpRichEditOle);
|
||||
@ -1624,10 +1790,17 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey)
|
||||
}
|
||||
else if (ME_ArrowKey(editor, VK_LEFT, FALSE, FALSE))
|
||||
{
|
||||
/* Backspace can be grouped for a single undo */
|
||||
ME_ContinueCoalescingTransaction(editor);
|
||||
ME_DeleteTextAtCursor(editor, 1, 1);
|
||||
ME_CommitCoalescingUndo(editor);
|
||||
BOOL bDeletionSucceeded;
|
||||
/* Backspace can be grouped for a single undo */
|
||||
ME_ContinueCoalescingTransaction(editor);
|
||||
bDeletionSucceeded = ME_DeleteTextAtCursor(editor, 1, 1);
|
||||
if (!bDeletionSucceeded && !editor->bEmulateVersion10) { /* v4.1 */
|
||||
/* Deletion was prevented so the cursor is moved back to where it was.
|
||||
* (e.g. this happens when trying to delete cell boundaries)
|
||||
*/
|
||||
ME_ArrowKey(editor, VK_RIGHT, FALSE, FALSE);
|
||||
}
|
||||
ME_CommitCoalescingUndo(editor);
|
||||
}
|
||||
else
|
||||
return TRUE;
|
||||
@ -2503,10 +2676,10 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
|
||||
if (p->type == diTextEnd)
|
||||
break;
|
||||
if (p->type == diParagraph) {
|
||||
ypara = p->member.para.nYPos;
|
||||
ypara = p->member.para.pt.y;
|
||||
continue;
|
||||
}
|
||||
ystart = ypara + p->member.row.nYPos;
|
||||
ystart = ypara + p->member.row.pt.y;
|
||||
yend = ystart + p->member.row.nHeight;
|
||||
if (y < yend) {
|
||||
break;
|
||||
@ -2572,7 +2745,7 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
|
||||
nPos = ME_GetYScrollPos(editor);
|
||||
row = ME_RowStart(editor->pCursors[0].pRun);
|
||||
para = ME_GetParagraph(row);
|
||||
top = para->member.para.nYPos + row->member.row.nYPos;
|
||||
top = para->member.para.pt.y + row->member.row.pt.y;
|
||||
bottom = top + row->member.row.nHeight;
|
||||
|
||||
if (top < nPos) /* caret above window */
|
||||
@ -3089,10 +3262,10 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
|
||||
assert(pRun->type == diRun);
|
||||
pt.y = pRun->member.run.pt.y;
|
||||
pt.x = pRun->member.run.pt.x + ME_PointFromChar(editor, &pRun->member.run, nOffset);
|
||||
pt.y += ME_GetParagraph(pRun)->member.para.nYPos;
|
||||
pt.y += ME_GetParagraph(pRun)->member.para.pt.y;
|
||||
} else {
|
||||
pt.x = 0;
|
||||
pt.y = editor->pBuffer->pLast->member.para.nYPos;
|
||||
pt.y = editor->pBuffer->pLast->member.para.pt.y;
|
||||
}
|
||||
pt.x += editor->selofs;
|
||||
|
||||
@ -3287,8 +3460,13 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
|
||||
|| (wstr=='\r' && (GetWindowLongW(hWnd, GWL_STYLE) & ES_MULTILINE))
|
||||
|| wstr=='\t') {
|
||||
int from, to;
|
||||
BOOL ctrl_is_down = GetKeyState(VK_CONTROL) & 0x8000;
|
||||
ME_GetSelection(editor, &from, &to);
|
||||
if (wstr=='\t') {
|
||||
if (wstr=='\t'
|
||||
/* v4.1 allows tabs to be inserted with ctrl key down */
|
||||
&& !(ctrl_is_down && !editor->bEmulateVersion10)
|
||||
)
|
||||
{
|
||||
ME_Cursor cursor = editor->pCursors[0];
|
||||
ME_DisplayItem *para;
|
||||
BOOL bSelectedRow = FALSE;
|
||||
@ -3726,7 +3904,12 @@ int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, in
|
||||
if (nLen > nChars)
|
||||
nLen = nChars;
|
||||
|
||||
if (item->member.run.nFlags & MERF_ENDPARA)
|
||||
if (item->member.run.nFlags & MERF_ENDCELL &&
|
||||
item->member.run.nFlags & MERF_ENDPARA)
|
||||
{
|
||||
*buffer = '\t';
|
||||
}
|
||||
else if (item->member.run.nFlags & MERF_ENDPARA)
|
||||
{
|
||||
if (!ME_FindItemFwd(item, diRun))
|
||||
/* No '\r' is appended to the last paragraph. */
|
||||
@ -3738,10 +3921,16 @@ int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, in
|
||||
if (bCRLF)
|
||||
{
|
||||
/* richedit 2.0 case - actual line-break is \r but should report \r\n */
|
||||
assert(nLen == 1);
|
||||
if (ME_GetParagraph(item)->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND))
|
||||
assert(nLen == 2);
|
||||
else
|
||||
assert(nLen == 1);
|
||||
*buffer++ = '\r';
|
||||
*buffer = '\n'; /* Later updated by nLen==1 at the end of the loop */
|
||||
nWritten++;
|
||||
if (nLen == 1)
|
||||
nWritten++;
|
||||
else
|
||||
buffer--;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -217,7 +217,7 @@ void ME_SendRequestResize(ME_TextEditor *editor, BOOL force);
|
||||
ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *run);
|
||||
void ME_GetSelectionParas(ME_TextEditor *editor, ME_DisplayItem **para, ME_DisplayItem **para_end);
|
||||
void ME_MakeFirstParagraph(ME_TextEditor *editor);
|
||||
ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *rp, ME_Style *style, int numCR, int numLF);
|
||||
ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *rp, ME_Style *style, int numCR, int numLF, int paraFlags);
|
||||
ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp,
|
||||
BOOL keepFirstParaFormat);
|
||||
void ME_DumpParaStyle(ME_Paragraph *s);
|
||||
@ -287,6 +287,14 @@ void ME_UpdateSelectionLinkAttribute(ME_TextEditor *editor);
|
||||
|
||||
/* table.c */
|
||||
BOOL ME_IsInTable(ME_DisplayItem *pItem);
|
||||
ME_DisplayItem *ME_InsertTableRowStartFromCursor(ME_TextEditor *editor);
|
||||
ME_DisplayItem *ME_InsertTableRowStartAtParagraph(ME_TextEditor *editor,
|
||||
ME_DisplayItem *para);
|
||||
ME_DisplayItem *ME_InsertTableCellFromCursor(ME_TextEditor *editor);
|
||||
ME_DisplayItem *ME_InsertTableRowEndFromCursor(ME_TextEditor *editor);
|
||||
ME_DisplayItem *ME_GetTableRowEnd(ME_DisplayItem *para);
|
||||
ME_DisplayItem *ME_GetTableRowStart(ME_DisplayItem *para);
|
||||
void ME_CheckTablesForCorruption(ME_TextEditor *editor);
|
||||
void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, int nOfs,int *nChars);
|
||||
void ME_TabPressedInTable(ME_TextEditor *editor, BOOL bSelectedRow);
|
||||
|
||||
|
@ -67,26 +67,27 @@ typedef enum {
|
||||
diInvalid,
|
||||
diTextStart, /* start of the text buffer */
|
||||
diParagraph, /* paragraph start */
|
||||
diCell, /* cell start */
|
||||
diRun, /* run (sequence of chars with the same character format) */
|
||||
diStartRow, /* start of the row (line of text on the screen) */
|
||||
diTextEnd, /* end of the text buffer */
|
||||
|
||||
/********************* these below are meant for finding only *********************/
|
||||
diStartRowOrParagraph, /* 5 */
|
||||
diStartRowOrParagraph, /* 7 */
|
||||
diStartRowOrParagraphOrEnd,
|
||||
diRunOrParagraph,
|
||||
diRunOrStartRow,
|
||||
diParagraphOrEnd,
|
||||
diRunOrParagraphOrEnd, /* 10 */
|
||||
diRunOrParagraphOrEnd, /* 12 */
|
||||
|
||||
diUndoInsertRun, /* 11 */
|
||||
diUndoDeleteRun, /* 12 */
|
||||
diUndoJoinParagraphs, /* 13 */
|
||||
diUndoSplitParagraph, /* 14 */
|
||||
diUndoSetParagraphFormat, /* 15 */
|
||||
diUndoSetCharFormat, /* 16 */
|
||||
diUndoEndTransaction, /* 17 - marks the end of a group of changes for undo */
|
||||
diUndoPotentialEndTransaction, /* 18 - allows grouping typed chars for undo */
|
||||
diUndoInsertRun, /* 13 */
|
||||
diUndoDeleteRun, /* 14 */
|
||||
diUndoJoinParagraphs, /* 15 */
|
||||
diUndoSplitParagraph, /* 16 */
|
||||
diUndoSetParagraphFormat, /* 17 */
|
||||
diUndoSetCharFormat, /* 18 */
|
||||
diUndoEndTransaction, /* 19 - marks the end of a group of changes for undo */
|
||||
diUndoPotentialEndTransaction, /* 20 - allows grouping typed chars for undo */
|
||||
} ME_DIType;
|
||||
|
||||
#define SELECTIONBAR_WIDTH 9
|
||||
@ -97,8 +98,10 @@ typedef enum {
|
||||
#define MERF_GRAPHICS 0x001
|
||||
/* run is a tab (or, in future, any kind of content whose size is dependent on run position) */
|
||||
#define MERF_TAB 0x002
|
||||
/* run is a cell boundary */
|
||||
#define MERF_ENDCELL 0x004 /* v4.1 */
|
||||
|
||||
#define MERF_NONTEXT (MERF_GRAPHICS | MERF_TAB)
|
||||
#define MERF_NONTEXT (MERF_GRAPHICS | MERF_TAB | MERF_ENDCELL)
|
||||
|
||||
/* run is splittable (contains white spaces in the middle or end) */
|
||||
#define MERF_SPLITTABLE 0x001000
|
||||
@ -118,6 +121,8 @@ typedef enum {
|
||||
#define MERF_ENDROW 0x200000
|
||||
/* run is hidden */
|
||||
#define MERF_HIDDEN 0x400000
|
||||
/* start of a table row has an empty paragraph that should be skipped over. */
|
||||
#define MERF_TABLESTART 0x800000 /* v4.1 */
|
||||
|
||||
/* runs with any of these flags set cannot be joined */
|
||||
#define MERF_NOJOIN (MERF_GRAPHICS|MERF_TAB|MERF_ENDPARA|MERF_ENDROW)
|
||||
@ -130,8 +135,12 @@ typedef enum {
|
||||
/******************************** para flags *************************/
|
||||
|
||||
/* this paragraph was already wrapped and hasn't changed, every change resets that flag */
|
||||
#define MEPF_REWRAP 1
|
||||
#define MEPF_REPAINT 2
|
||||
#define MEPF_REWRAP 0x01
|
||||
#define MEPF_REPAINT 0x02
|
||||
/* v4.1 */
|
||||
#define MEPF_CELL 0x04 /* The paragraph is nested in a cell */
|
||||
#define MEPF_ROWSTART 0x08 /* Hidden empty paragraph at the start of the row */
|
||||
#define MEPF_ROWEND 0x10 /* Visible empty paragraph at the end of the row */
|
||||
|
||||
/******************************** structures *************************/
|
||||
|
||||
@ -160,14 +169,26 @@ typedef struct tagME_Paragraph
|
||||
{
|
||||
PARAFORMAT2 *pFmt;
|
||||
|
||||
struct tagME_DisplayItem *pCell; /* v4.1 */
|
||||
|
||||
int nCharOfs;
|
||||
int nFlags;
|
||||
int nYPos, nHeight;
|
||||
POINT pt;
|
||||
int nHeight;
|
||||
int nLastPaintYPos, nLastPaintHeight;
|
||||
int nRows;
|
||||
struct tagME_DisplayItem *prev_para, *next_para, *document;
|
||||
} ME_Paragraph;
|
||||
|
||||
typedef struct tagME_Cell /* v4.1 */
|
||||
{
|
||||
int nNestingLevel; /* 0 for normal cells, and greater for nested cells */
|
||||
int nRightBoundary;
|
||||
POINT pt;
|
||||
int nHeight, nWidth;
|
||||
struct tagME_DisplayItem *prev_cell, *next_cell, *parent_cell;
|
||||
} ME_Cell;
|
||||
|
||||
typedef struct tagME_Row
|
||||
{
|
||||
int nHeight;
|
||||
@ -175,7 +196,7 @@ typedef struct tagME_Row
|
||||
int nWidth;
|
||||
int nLMargin;
|
||||
int nRMargin;
|
||||
int nYPos;
|
||||
POINT pt;
|
||||
} ME_Row;
|
||||
|
||||
/* the display item list layout is like this:
|
||||
@ -197,6 +218,7 @@ typedef struct tagME_DisplayItem
|
||||
union {
|
||||
ME_Run run;
|
||||
ME_Row row;
|
||||
ME_Cell cell;
|
||||
ME_Paragraph para;
|
||||
ME_Document doc; /* not used */
|
||||
ME_Style *ustyle; /* used by diUndoSetCharFormat */
|
||||
@ -270,6 +292,9 @@ typedef struct tagME_OutStream {
|
||||
COLORREF colortbl[STREAMOUT_COLORTBL_SIZE];
|
||||
UINT nDefaultFont;
|
||||
UINT nDefaultCodePage;
|
||||
/* nNestingLevel = 0 means we aren't in a cell, 1 means we are in a cell,
|
||||
* an greater numbers mean we are in a cell nested within a cell. */
|
||||
UINT nNestingLevel;
|
||||
} ME_OutStream;
|
||||
|
||||
typedef struct tagME_FontCacheItem
|
||||
|
@ -121,8 +121,11 @@ void ME_DestroyDisplayItem(ME_DisplayItem *item) {
|
||||
if (item->type==diUndoSetCharFormat) {
|
||||
ME_ReleaseStyle(item->member.ustyle);
|
||||
}
|
||||
if (item->type==diUndoSplitParagraph)
|
||||
if (item->type==diUndoSplitParagraph) {
|
||||
FREE_OBJ(item->member.para.pFmt);
|
||||
if (item->member.para.pCell)
|
||||
FREE_OBJ(item->member.para.pCell);
|
||||
}
|
||||
FREE_OBJ(item);
|
||||
}
|
||||
|
||||
@ -146,6 +149,7 @@ const char *ME_GetDITypeName(ME_DIType type)
|
||||
{
|
||||
case diParagraph: return "diParagraph";
|
||||
case diRun: return "diRun";
|
||||
case diCell: return "diCell";
|
||||
case diTextStart: return "diTextStart";
|
||||
case diTextEnd: return "diTextEnd";
|
||||
case diStartRow: return "diStartRow";
|
||||
@ -172,8 +176,17 @@ void ME_DumpDocument(ME_TextBuffer *buffer)
|
||||
case diTextStart:
|
||||
TRACE("Start\n");
|
||||
break;
|
||||
case diCell:
|
||||
TRACE("Cell(level=%d%s)\n", pItem->member.cell.nNestingLevel,
|
||||
!pItem->member.cell.next_cell ? ", END" :
|
||||
(!pItem->member.cell.prev_cell ? ", START" :""));
|
||||
break;
|
||||
case diParagraph:
|
||||
TRACE("Paragraph(ofs=%d)\n", pItem->member.para.nCharOfs);
|
||||
if (pItem->member.para.nFlags & MEPF_ROWSTART)
|
||||
TRACE(" - (Table Row Start)\n");
|
||||
if (pItem->member.para.nFlags & MEPF_ROWEND)
|
||||
TRACE(" - (Table Row End)\n");
|
||||
break;
|
||||
case diStartRow:
|
||||
TRACE(" - StartRow\n");
|
||||
|
@ -32,13 +32,21 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, const RECT *
|
||||
yoffset = ME_GetYScrollPos(editor);
|
||||
ME_InitContext(&c, editor, hDC);
|
||||
SetBkMode(hDC, TRANSPARENT);
|
||||
ME_MoveCaret(editor);
|
||||
ME_MoveCaret(editor); /* Calls ME_WrapMarkedParagraphs */
|
||||
item = editor->pBuffer->pFirst->next;
|
||||
c.pt.y -= yoffset;
|
||||
while(item != editor->pBuffer->pLast) {
|
||||
int ye;
|
||||
assert(item->type == diParagraph);
|
||||
ye = c.pt.y + item->member.para.nHeight;
|
||||
if (item->member.para.pCell
|
||||
!= item->member.para.next_para->member.para.pCell)
|
||||
{
|
||||
ME_Cell *cell = NULL;
|
||||
cell = &ME_FindItemBack(item->member.para.next_para, diCell)->member.cell;
|
||||
ye = cell->pt.y + cell->nHeight - yoffset;
|
||||
} else {
|
||||
ye = c.pt.y + item->member.para.nHeight;
|
||||
}
|
||||
if (!bOnlyNew || (item->member.para.nFlags & MEPF_REPAINT))
|
||||
{
|
||||
BOOL bPaint = (rcUpdate == NULL);
|
||||
@ -51,7 +59,31 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, const RECT *
|
||||
item->member.para.nFlags &= ~MEPF_REPAINT;
|
||||
}
|
||||
}
|
||||
c.pt.y = ye;
|
||||
if (item->member.para.pCell)
|
||||
{
|
||||
ME_Cell *cell = &item->member.para.pCell->member.cell;
|
||||
c.pt.x = cell->pt.x + cell->nWidth;
|
||||
if (item->member.para.pCell == item->member.para.next_para->member.para.pCell)
|
||||
{
|
||||
c.pt.y = ye;
|
||||
} else {
|
||||
if (item->member.para.next_para->member.para.nFlags & MEPF_ROWSTART)
|
||||
{
|
||||
cell = &ME_FindItemFwd(item->member.para.next_para, diCell)->member.cell;
|
||||
}
|
||||
else if (item->member.para.next_para->member.para.nFlags & MEPF_ROWEND)
|
||||
{
|
||||
cell = &cell->next_cell->member.cell;
|
||||
}
|
||||
else
|
||||
{
|
||||
cell = &item->member.para.next_para->member.para.pCell->member.cell;
|
||||
}
|
||||
c.pt.y = cell->pt.y - yoffset;
|
||||
}
|
||||
} else if (!(item->member.para.nFlags & MEPF_ROWSTART)) {
|
||||
c.pt.y = ye;
|
||||
}
|
||||
item = item->member.para.next_para;
|
||||
}
|
||||
if (c.pt.y<c.rcView.bottom) {
|
||||
@ -394,19 +426,19 @@ static void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Pa
|
||||
if (runofs >= nSelFrom && runofs < nSelTo)
|
||||
{
|
||||
ME_HighlightSpace(c, x, y, wszSpace, 1, run->style, 0, 0, 1,
|
||||
c->pt.y + start->member.row.nYPos,
|
||||
c->pt.y + start->member.row.pt.y,
|
||||
start->member.row.nHeight);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (run->nFlags & MERF_TAB)
|
||||
if (run->nFlags & (MERF_TAB | MERF_ENDCELL))
|
||||
{
|
||||
/* wszSpace is used instead of the tab character because otherwise
|
||||
* an unwanted symbol can be inserted instead. */
|
||||
ME_DrawTextWithStyle(c, x, y, wszSpace, 1, run->style, run->nWidth,
|
||||
nSelFrom-runofs,nSelTo-runofs,
|
||||
c->pt.y + start->member.row.nYPos,
|
||||
c->pt.y + start->member.row.pt.y,
|
||||
start->member.row.nHeight);
|
||||
return;
|
||||
}
|
||||
@ -420,13 +452,13 @@ static void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Pa
|
||||
ME_String *szMasked = ME_MakeStringR(c->editor->cPasswordMask,ME_StrVLen(run->strText));
|
||||
ME_DrawTextWithStyle(c, x, y,
|
||||
szMasked->szData, ME_StrVLen(szMasked), run->style, run->nWidth,
|
||||
nSelFrom-runofs,nSelTo-runofs, c->pt.y+start->member.row.nYPos, start->member.row.nHeight);
|
||||
nSelFrom-runofs,nSelTo-runofs, c->pt.y+start->member.row.pt.y, start->member.row.nHeight);
|
||||
ME_DestroyString(szMasked);
|
||||
}
|
||||
else
|
||||
ME_DrawTextWithStyle(c, x, y,
|
||||
run->strText->szData, ME_StrVLen(run->strText), run->style, run->nWidth,
|
||||
nSelFrom-runofs,nSelTo-runofs, c->pt.y+start->member.row.nYPos, start->member.row.nHeight);
|
||||
nSelFrom-runofs,nSelTo-runofs, c->pt.y+start->member.row.pt.y, start->member.row.nHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@ -635,23 +667,38 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
|
||||
ME_DisplayItem *p;
|
||||
ME_Run *run;
|
||||
ME_Paragraph *para = NULL;
|
||||
RECT rc, rcPara, bounds;
|
||||
RECT rc, rcText, bounds;
|
||||
int y = c->pt.y;
|
||||
int height = 0, baseline = 0, no=0, pno = 0;
|
||||
int xs = 0, xe = 0;
|
||||
BOOL visible = FALSE;
|
||||
|
||||
c->pt.x = c->rcView.left;
|
||||
rcPara.left = c->rcView.left;
|
||||
rcPara.right = c->rcView.right;
|
||||
rc.left = c->rcView.left;
|
||||
rc.right = c->rcView.right;
|
||||
for (p = paragraph; p!=paragraph->member.para.next_para; p = p->next) {
|
||||
switch(p->type) {
|
||||
case diParagraph:
|
||||
para = &p->member.para;
|
||||
assert(para);
|
||||
pno = 0;
|
||||
xs = c->rcView.left + ME_twips2pointsX(c, para->pFmt->dxStartIndent);
|
||||
xe = c->rcView.right - ME_twips2pointsX(c, para->pFmt->dxRightIndent);
|
||||
if (para->pCell)
|
||||
{
|
||||
ME_Cell *cell = ¶->pCell->member.cell;
|
||||
rc.left = cell->pt.x;
|
||||
rc.right = rc.left + cell->nWidth;
|
||||
rcText.left = cell->pt.x + ME_twips2pointsX(c, para->pFmt->dxStartIndent);
|
||||
rcText.right = cell->pt.x + cell->nWidth
|
||||
- ME_twips2pointsX(c, para->pFmt->dxRightIndent);
|
||||
}
|
||||
if (para->nFlags & MEPF_ROWSTART) {
|
||||
ME_Cell *cell = ¶->next_para->member.para.pCell->member.cell;
|
||||
rc.right = cell->pt.x;
|
||||
} else if (para->nFlags & MEPF_ROWEND) {
|
||||
ME_Cell *cell = ¶->prev_para->member.para.pCell->member.cell;
|
||||
rc.left = cell->pt.x + cell->nWidth;
|
||||
}
|
||||
rcText.left = rc.left + ME_twips2pointsX(c, para->pFmt->dxStartIndent);
|
||||
rcText.right = rc.right - ME_twips2pointsX(c, para->pFmt->dxRightIndent);
|
||||
ME_DrawParaDecoration(c, para, y, &bounds);
|
||||
y += bounds.top;
|
||||
break;
|
||||
@ -659,22 +706,18 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
|
||||
/* we should have seen a diParagraph before */
|
||||
assert(para);
|
||||
y += height;
|
||||
rcPara.top = y;
|
||||
rcPara.bottom = y+p->member.row.nHeight;
|
||||
visible = RectVisible(c->hDC, &rcPara);
|
||||
if (visible) {
|
||||
/* left margin */
|
||||
rc.left = c->rcView.left + bounds.left;
|
||||
rc.right = xs;
|
||||
rc.top = y;
|
||||
rc.top = y;
|
||||
if (para->nFlags & MEPF_ROWSTART) {
|
||||
ME_Cell *cell = ¶->next_para->member.para.pCell->member.cell;
|
||||
rc.bottom = y + cell->nHeight;
|
||||
} else if (para->nFlags & MEPF_ROWEND) {
|
||||
ME_Cell *cell = ¶->prev_para->member.para.pCell->member.cell;
|
||||
rc.bottom = y + cell->nHeight;
|
||||
} else {
|
||||
rc.bottom = y+p->member.row.nHeight;
|
||||
FillRect(c->hDC, &rc, c->editor->hbrBackground);
|
||||
/* right margin */
|
||||
rc.left = xe;
|
||||
rc.right = c->rcView.right - bounds.right;
|
||||
FillRect(c->hDC, &rc, c->editor->hbrBackground);
|
||||
rc.left = xs;
|
||||
rc.right = xe;
|
||||
}
|
||||
visible = RectVisible(c->hDC, &rc);
|
||||
if (visible) {
|
||||
FillRect(c->hDC, &rc, c->editor->hbrBackground);
|
||||
}
|
||||
if (me_debug)
|
||||
@ -690,7 +733,7 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
|
||||
height = p->member.row.nHeight;
|
||||
baseline = p->member.row.nBaseline;
|
||||
if (!pno++)
|
||||
xe += ME_twips2pointsX(c, para->pFmt->dxOffset);
|
||||
rcText.right += ME_twips2pointsX(c, para->pFmt->dxOffset);
|
||||
break;
|
||||
case diRun:
|
||||
assert(para);
|
||||
@ -721,6 +764,18 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
|
||||
}
|
||||
/* c->pt.x += p->member.run.nWidth; */
|
||||
break;
|
||||
case diCell:
|
||||
/* Clear any space at the bottom of the cell after the text. */
|
||||
if (para->nFlags & MEPF_ROWSTART)
|
||||
break;
|
||||
y += height;
|
||||
rc.top = y;
|
||||
rc.bottom = p->member.cell.pt.y + p->member.cell.nHeight
|
||||
- ME_GetYScrollPos(c->editor);
|
||||
if (RectVisible(c->hDC, &rc))
|
||||
{
|
||||
FillRect(c->hDC, &rc, c->editor->hbrBackground);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -867,7 +922,7 @@ void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun)
|
||||
assert(pRow);
|
||||
assert(pPara);
|
||||
|
||||
y = pPara->member.para.nYPos+pRow->member.row.nYPos;
|
||||
y = pPara->member.para.pt.y+pRow->member.row.pt.y;
|
||||
yheight = pRow->member.row.nHeight;
|
||||
yold = ME_GetYScrollPos(editor);
|
||||
yrel = y - yold;
|
||||
|
@ -104,17 +104,51 @@ void ME_MarkForPainting(ME_TextEditor *editor, ME_DisplayItem *first, const ME_D
|
||||
}
|
||||
}
|
||||
|
||||
static void ME_UpdateTableFlags(ME_DisplayItem *para)
|
||||
{
|
||||
para->member.para.pFmt->dwMask |= PFM_TABLE|PFM_TABLEROWDELIMITER;
|
||||
if (para->member.para.pCell) {
|
||||
para->member.para.nFlags |= MEPF_CELL;
|
||||
} else {
|
||||
para->member.para.nFlags &= ~MEPF_CELL;
|
||||
}
|
||||
if (para->member.para.nFlags & MEPF_ROWEND) {
|
||||
para->member.para.pFmt->wEffects |= PFE_TABLEROWDELIMITER;
|
||||
} else {
|
||||
para->member.para.pFmt->wEffects &= ~PFE_TABLEROWDELIMITER;
|
||||
}
|
||||
if (para->member.para.nFlags & (MEPF_ROWSTART|MEPF_CELL|MEPF_ROWEND))
|
||||
para->member.para.pFmt->wEffects |= PFE_TABLE;
|
||||
else
|
||||
para->member.para.pFmt->wEffects &= ~PFE_TABLE;
|
||||
}
|
||||
|
||||
/* split paragraph at the beginning of the run */
|
||||
ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, ME_Style *style, int numCR, int numLF)
|
||||
ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run,
|
||||
ME_Style *style, int numCR, int numLF,
|
||||
int paraFlags)
|
||||
{
|
||||
ME_DisplayItem *next_para = NULL;
|
||||
ME_DisplayItem *run_para = NULL;
|
||||
ME_DisplayItem *new_para = ME_MakeDI(diParagraph);
|
||||
ME_DisplayItem *end_run = ME_MakeRun(style,ME_MakeString(wszParagraphSign), MERF_ENDPARA);
|
||||
ME_DisplayItem *end_run;
|
||||
ME_UndoItem *undo = NULL;
|
||||
int ofs;
|
||||
ME_DisplayItem *pp;
|
||||
int end_len = numCR + numLF;
|
||||
int run_flags = MERF_ENDPARA;
|
||||
if (!editor->bEmulateVersion10) { /* v4.1 */
|
||||
/* At most 1 of MEPF_CELL, MEPF_ROWSTART, or MEPF_ROWEND should be set. */
|
||||
assert(!(paraFlags & ~(MEPF_CELL|MEPF_ROWSTART|MEPF_ROWEND)));
|
||||
assert(!(paraFlags & (paraFlags-1)));
|
||||
if (paraFlags == MEPF_CELL)
|
||||
run_flags |= MERF_ENDCELL;
|
||||
else if (paraFlags == MEPF_ROWSTART)
|
||||
run_flags |= MERF_TABLESTART|MERF_HIDDEN;
|
||||
} else { /* v1.0 - v3.0 */
|
||||
assert(!(paraFlags & (MEPF_CELL|MEPF_ROWSTART|MEPF_ROWEND)));
|
||||
}
|
||||
end_run = ME_MakeRun(style,ME_MakeString(wszParagraphSign), run_flags);
|
||||
|
||||
assert(run->type == diRun);
|
||||
|
||||
@ -139,11 +173,11 @@ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, ME
|
||||
}
|
||||
new_para->member.para.nCharOfs = ME_GetParagraph(run)->member.para.nCharOfs+ofs;
|
||||
new_para->member.para.nCharOfs += end_len;
|
||||
|
||||
new_para->member.para.nFlags = MEPF_REWRAP; /* FIXME copy flags (if applicable) */
|
||||
new_para->member.para.nFlags = MEPF_REWRAP;
|
||||
|
||||
/* FIXME initialize format style and call ME_SetParaFormat blah blah */
|
||||
*new_para->member.para.pFmt = *run_para->member.para.pFmt;
|
||||
|
||||
|
||||
/* insert paragraph into paragraph double linked list */
|
||||
new_para->member.para.prev_para = run_para;
|
||||
new_para->member.para.next_para = next_para;
|
||||
@ -154,6 +188,44 @@ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, ME
|
||||
ME_InsertBefore(run, new_para);
|
||||
ME_InsertBefore(new_para, end_run);
|
||||
|
||||
if (!editor->bEmulateVersion10) { /* v4.1 */
|
||||
if (paraFlags & (MEPF_ROWSTART|MEPF_CELL))
|
||||
{
|
||||
ME_DisplayItem *cell = ME_MakeDI(diCell);
|
||||
ME_InsertBefore(new_para, cell);
|
||||
new_para->member.para.pCell = cell;
|
||||
cell->member.cell.next_cell = NULL;
|
||||
if (paraFlags & MEPF_ROWSTART)
|
||||
{
|
||||
run_para->member.para.nFlags |= MEPF_ROWSTART;
|
||||
cell->member.cell.prev_cell = NULL;
|
||||
cell->member.cell.parent_cell = run_para->member.para.pCell;
|
||||
if (run_para->member.para.pCell)
|
||||
cell->member.cell.nNestingLevel = run_para->member.para.pCell->member.cell.nNestingLevel + 1;
|
||||
else
|
||||
cell->member.cell.nNestingLevel = 1;
|
||||
} else {
|
||||
cell->member.cell.prev_cell = run_para->member.para.pCell;
|
||||
assert(cell->member.cell.prev_cell);
|
||||
cell->member.cell.prev_cell->member.cell.next_cell = cell;
|
||||
assert(run_para->member.para.nFlags & MEPF_CELL);
|
||||
assert(!(run_para->member.para.nFlags & MEPF_ROWSTART));
|
||||
cell->member.cell.nNestingLevel = cell->member.cell.prev_cell->member.cell.nNestingLevel;
|
||||
cell->member.cell.parent_cell = cell->member.cell.prev_cell->member.cell.parent_cell;
|
||||
}
|
||||
} else if (paraFlags & MEPF_ROWEND) {
|
||||
run_para->member.para.nFlags |= MEPF_ROWEND;
|
||||
run_para->member.para.pCell = run_para->member.para.pCell->member.cell.parent_cell;
|
||||
new_para->member.para.pCell = run_para->member.para.pCell;
|
||||
assert(run_para->member.para.prev_para->member.para.nFlags & MEPF_CELL);
|
||||
assert(!(run_para->member.para.prev_para->member.para.nFlags & MEPF_ROWSTART));
|
||||
} else {
|
||||
new_para->member.para.pCell = run_para->member.para.pCell;
|
||||
}
|
||||
ME_UpdateTableFlags(run_para);
|
||||
ME_UpdateTableFlags(new_para);
|
||||
}
|
||||
|
||||
/* force rewrap of the */
|
||||
run_para->member.para.prev_para->member.para.nFlags |= MEPF_REWRAP;
|
||||
new_para->member.para.prev_para->member.para.nFlags |= MEPF_REWRAP;
|
||||
@ -208,6 +280,42 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp,
|
||||
ME_AddUndoItem(editor, diUndoSetParagraphFormat, tp);
|
||||
*tp->member.para.pFmt = *pNext->member.para.pFmt;
|
||||
}
|
||||
|
||||
if (!editor->bEmulateVersion10) { /* v4.1 */
|
||||
/* Table cell/row properties are always moved over from the removed para. */
|
||||
tp->member.para.nFlags = pNext->member.para.nFlags;
|
||||
tp->member.para.pCell = pNext->member.para.pCell;
|
||||
|
||||
/* Remove cell boundary if it is between the end paragraph run and the next
|
||||
* paragraph display item. */
|
||||
pTmp = pRun->next;
|
||||
while (pTmp != pNext) {
|
||||
if (pTmp->type == diCell)
|
||||
{
|
||||
ME_Cell *pCell = &pTmp->member.cell;
|
||||
if (undo)
|
||||
{
|
||||
assert(!(undo->di.member.para.nFlags & MEPF_ROWEND));
|
||||
if (!(undo->di.member.para.nFlags & MEPF_ROWSTART))
|
||||
undo->di.member.para.nFlags |= MEPF_CELL;
|
||||
undo->di.member.para.pCell = ALLOC_OBJ(ME_DisplayItem);
|
||||
*undo->di.member.para.pCell = *pTmp;
|
||||
undo->di.member.para.pCell->next = NULL;
|
||||
undo->di.member.para.pCell->prev = NULL;
|
||||
undo->di.member.para.pCell->member.cell.next_cell = NULL;
|
||||
undo->di.member.para.pCell->member.cell.prev_cell = NULL;
|
||||
}
|
||||
ME_Remove(pTmp);
|
||||
if (pCell->prev_cell)
|
||||
pCell->prev_cell->member.cell.next_cell = pCell->next_cell;
|
||||
if (pCell->next_cell)
|
||||
pCell->next_cell->member.cell.prev_cell = pCell->prev_cell;
|
||||
ME_DestroyDisplayItem(pTmp);
|
||||
break;
|
||||
}
|
||||
pTmp = pTmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
shift = pNext->member.para.nCharOfs - tp->member.para.nCharOfs - end_len;
|
||||
|
||||
|
@ -1012,7 +1012,15 @@ struct RTFTable
|
||||
{
|
||||
RTFCell cells[MAX_TABLE_CELLS];
|
||||
int numCellsDefined;
|
||||
|
||||
/* Used in v1.0 - v3.0 */
|
||||
int numCellsInserted;
|
||||
|
||||
/* v4.1 */
|
||||
/* tableRowStart may be the start row paragraph of the table row,
|
||||
* or it may store the end of the previous row if it may still be
|
||||
* continued, otherwise NULL is stored. */
|
||||
ME_DisplayItem *tableRowStart;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -134,6 +134,9 @@ void ME_CheckCharOffsets(ME_TextEditor *editor)
|
||||
else
|
||||
ofs += ME_StrLen(p->member.run.strText);
|
||||
break;
|
||||
case diCell:
|
||||
TRACE_(richedit_check)("cell\n");
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
@ -436,7 +439,7 @@ void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run)
|
||||
{
|
||||
assert(run->nCharOfs != -1);
|
||||
|
||||
if (RUN_IS_HIDDEN(run))
|
||||
if (RUN_IS_HIDDEN(run) || run->nFlags & MERF_TABLESTART)
|
||||
run->nFlags |= MERF_HIDDEN;
|
||||
else
|
||||
run->nFlags &= ~MERF_HIDDEN;
|
||||
@ -483,7 +486,8 @@ int ME_CharFromPoint(ME_Context *c, int cx, ME_Run *run)
|
||||
if (!run->strText->nLen)
|
||||
return 0;
|
||||
|
||||
if (run->nFlags & MERF_TAB)
|
||||
if (run->nFlags & MERF_TAB ||
|
||||
(run->nFlags & (MERF_ENDCELL|MERF_ENDPARA)) == MERF_ENDCELL)
|
||||
{
|
||||
if (cx < run->nWidth/2)
|
||||
return 0;
|
||||
@ -540,7 +544,7 @@ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run)
|
||||
if (!run->strText->nLen)
|
||||
return 0;
|
||||
|
||||
if (run->nFlags & MERF_TAB)
|
||||
if (run->nFlags & (MERF_TAB | MERF_ENDCELL))
|
||||
{
|
||||
if (cx < run->nWidth/2)
|
||||
return 0;
|
||||
|
@ -21,18 +21,236 @@
|
||||
/*
|
||||
* The implementation of tables differs greatly between version 3.0
|
||||
* (in riched20.dll) and version 4.1 (in msftedit.dll) of richedit controls.
|
||||
* Currently Wine is not implementing table support as done in version 4.1.
|
||||
* Currently Wine is not distinguishing between version 3.0 and version 4.1,
|
||||
* so v4.1 is assumed unless v1.0 is being emulated (i.e. riched32.dll is used).
|
||||
* If this lack of distinction causes a bug in a Windows application, then Wine
|
||||
* will need to start making this distinction.
|
||||
*
|
||||
* Richedit version 1.0 - 3.0:
|
||||
* Tables are implemented in these versions using tabs at the end of cells,
|
||||
* and tab stops to position the cells. The paragraph format flag PFE_TABLE
|
||||
* will indicate the the paragraph is a table row. Note that in this
|
||||
* implementation there is one paragraph per table row.
|
||||
*
|
||||
* Richedit version 4.1:
|
||||
* Tables are implemented such that cells can contain multiple paragraphs,
|
||||
* each with it's own paragraph format, and cells may even contain tables
|
||||
* nested within the cell.
|
||||
*
|
||||
* There are is also a paragraph at the start of each table row that contains
|
||||
* the rows paragraph format (e.g. to change the row alignment to row), and a
|
||||
* paragraph at the end of the table row with the PFE_TABLEROWDELIMITER flag
|
||||
* set. The paragraphs at the start and end of the table row should always be
|
||||
* empty, but should have a length of 2.
|
||||
*
|
||||
* Wine implements this using display items (ME_DisplayItem) with a type of
|
||||
* diCell. These cell display items store the cell properties, and are
|
||||
* inserted into the editors linked list before each cell, and at the end of
|
||||
* the last cell. The cell display item for a cell comes before the paragraphs
|
||||
* for the cell, but the last cell display item refers to no cell, so it is
|
||||
* just a delimiter.
|
||||
*/
|
||||
|
||||
#include "editor.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(richedit);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(richedit_lists);
|
||||
|
||||
static ME_DisplayItem* ME_InsertEndParaFromCursor(ME_TextEditor *editor,
|
||||
int nCursor,
|
||||
int numCR,
|
||||
int numLF,
|
||||
int paraFlags)
|
||||
{
|
||||
ME_Style *pStyle = ME_GetInsertStyle(editor, nCursor);
|
||||
ME_DisplayItem *tp;
|
||||
ME_Cursor* cursor = &editor->pCursors[nCursor];
|
||||
if (cursor->nOffset) {
|
||||
ME_SplitRunSimple(editor, cursor->pRun, cursor->nOffset);
|
||||
cursor = &editor->pCursors[nCursor];
|
||||
}
|
||||
|
||||
tp = ME_SplitParagraph(editor, cursor->pRun, pStyle, numCR, numLF, paraFlags);
|
||||
cursor->pRun = ME_FindItemFwd(tp, diRun);
|
||||
return tp;
|
||||
}
|
||||
|
||||
ME_DisplayItem* ME_InsertTableRowStartFromCursor(ME_TextEditor *editor)
|
||||
{
|
||||
ME_DisplayItem *para;
|
||||
para = ME_InsertEndParaFromCursor(editor, 0, 1, 1, MEPF_ROWSTART);
|
||||
return para->member.para.prev_para;
|
||||
}
|
||||
|
||||
ME_DisplayItem* ME_InsertTableRowStartAtParagraph(ME_TextEditor *editor,
|
||||
ME_DisplayItem *para)
|
||||
{
|
||||
ME_DisplayItem *prev_para, *end_para;
|
||||
ME_Cursor savedCursor = editor->pCursors[0];
|
||||
ME_DisplayItem *startRowPara;
|
||||
editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun);
|
||||
editor->pCursors[0].nOffset = 0;
|
||||
editor->pCursors[1] = editor->pCursors[0];
|
||||
startRowPara = ME_InsertTableRowStartFromCursor(editor);
|
||||
editor->pCursors[0] = savedCursor;
|
||||
editor->pCursors[1] = editor->pCursors[0];
|
||||
|
||||
end_para = ME_GetParagraph(editor->pCursors[0].pRun)->member.para.next_para;
|
||||
prev_para = startRowPara->member.para.next_para;
|
||||
para = prev_para->member.para.next_para;
|
||||
while (para != end_para)
|
||||
{
|
||||
para->member.para.pCell = prev_para->member.para.pCell;
|
||||
para->member.para.nFlags |= MEPF_CELL;
|
||||
para->member.para.nFlags &= ~(MEPF_ROWSTART|MEPF_ROWEND);
|
||||
para->member.para.pFmt->dwMask |= PFM_TABLE|PFM_TABLEROWDELIMITER;
|
||||
para->member.para.pFmt->wEffects |= PFE_TABLE;
|
||||
para->member.para.pFmt->wEffects &= ~PFE_TABLEROWDELIMITER;
|
||||
prev_para = para;
|
||||
para = para->member.para.next_para;
|
||||
}
|
||||
return startRowPara;
|
||||
}
|
||||
|
||||
/* Inserts a diCell and starts a new paragraph for the next cell.
|
||||
*
|
||||
* Returns the first paragraph of the new cell. */
|
||||
ME_DisplayItem* ME_InsertTableCellFromCursor(ME_TextEditor *editor)
|
||||
{
|
||||
ME_DisplayItem *para;
|
||||
para = ME_InsertEndParaFromCursor(editor, 0, 1, 0, MEPF_CELL);
|
||||
return para;
|
||||
}
|
||||
|
||||
ME_DisplayItem* ME_InsertTableRowEndFromCursor(ME_TextEditor *editor)
|
||||
{
|
||||
ME_DisplayItem *para;
|
||||
para = ME_InsertEndParaFromCursor(editor, 0, 1, 1, MEPF_ROWEND);
|
||||
return para->member.para.prev_para;
|
||||
}
|
||||
|
||||
ME_DisplayItem* ME_GetTableRowEnd(ME_DisplayItem *para)
|
||||
{
|
||||
ME_DisplayItem *cell;
|
||||
assert(para);
|
||||
if (para->member.para.nFlags & MEPF_ROWEND)
|
||||
return para;
|
||||
if (para->member.para.nFlags & MEPF_ROWSTART)
|
||||
para = para->member.para.next_para;
|
||||
cell = para->member.para.pCell;
|
||||
assert(cell && cell->type == diCell);
|
||||
while (cell->member.cell.next_cell)
|
||||
cell = cell->member.cell.next_cell;
|
||||
|
||||
para = ME_FindItemFwd(cell, diParagraph);
|
||||
assert(para && para->member.para.nFlags & MEPF_ROWEND);
|
||||
return para;
|
||||
}
|
||||
|
||||
ME_DisplayItem* ME_GetTableRowStart(ME_DisplayItem *para)
|
||||
{
|
||||
ME_DisplayItem *cell;
|
||||
assert(para);
|
||||
if (para->member.para.nFlags & MEPF_ROWSTART)
|
||||
return para;
|
||||
if (para->member.para.nFlags & MEPF_ROWEND)
|
||||
para = para->member.para.prev_para;
|
||||
cell = para->member.para.pCell;
|
||||
assert(cell && cell->type == diCell);
|
||||
while (cell->member.cell.prev_cell)
|
||||
cell = cell->member.cell.prev_cell;
|
||||
|
||||
para = ME_FindItemBack(cell, diParagraph);
|
||||
assert(para && para->member.para.nFlags & MEPF_ROWSTART);
|
||||
return para;
|
||||
}
|
||||
|
||||
/* Make a bunch of assertions to make sure tables haven't been corrupted.
|
||||
*
|
||||
* These invariants may not hold true in the middle of streaming in rich text
|
||||
* or during an undo and redo of streaming in rich text. It should be safe to
|
||||
* call this method after an event is processed.
|
||||
*/
|
||||
void ME_CheckTablesForCorruption(ME_TextEditor *editor)
|
||||
{
|
||||
if(TRACE_ON(richedit_lists))
|
||||
{
|
||||
TRACE_(richedit_lists)("---\n");
|
||||
ME_DumpDocument(editor->pBuffer);
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
ME_DisplayItem *p, *pPrev;
|
||||
pPrev = editor->pBuffer->pFirst;
|
||||
p = pPrev->next;
|
||||
if (!editor->bEmulateVersion10) /* v4.1 */
|
||||
{
|
||||
while (p->type == diParagraph)
|
||||
{
|
||||
assert(p->member.para.pFmt->dwMask & PFM_TABLE);
|
||||
assert(p->member.para.pFmt->dwMask & PFM_TABLEROWDELIMITER);
|
||||
if (p->member.para.pCell)
|
||||
{
|
||||
assert(p->member.para.nFlags & MEPF_CELL);
|
||||
assert(p->member.para.pFmt->wEffects & PFE_TABLE);
|
||||
}
|
||||
if (p->member.para.pCell != pPrev->member.para.pCell)
|
||||
{
|
||||
/* There must be a diCell in between the paragraphs if pCell changes. */
|
||||
ME_DisplayItem *pCell = ME_FindItemBack(p, diCell);
|
||||
assert(pCell);
|
||||
assert(ME_FindItemBack(p, diRun) == ME_FindItemBack(pCell, diRun));
|
||||
}
|
||||
if (p->member.para.nFlags & MEPF_ROWEND)
|
||||
{
|
||||
/* ROWEND must come after a cell. */
|
||||
assert(pPrev->member.para.pCell);
|
||||
assert(p->member.para.pCell
|
||||
== pPrev->member.para.pCell->member.cell.parent_cell);
|
||||
assert(p->member.para.pFmt->wEffects & PFE_TABLEROWDELIMITER);
|
||||
}
|
||||
else if (p->member.para.pCell)
|
||||
{
|
||||
assert(!(p->member.para.pFmt->wEffects & PFE_TABLEROWDELIMITER));
|
||||
assert(pPrev->member.para.pCell ||
|
||||
pPrev->member.para.nFlags & MEPF_ROWSTART);
|
||||
if (pPrev->member.para.pCell &&
|
||||
!(pPrev->member.para.nFlags & MEPF_ROWSTART))
|
||||
{
|
||||
assert(p->member.para.pCell->member.cell.parent_cell
|
||||
== pPrev->member.para.pCell->member.cell.parent_cell);
|
||||
if (pPrev->member.para.pCell != p->member.para.pCell)
|
||||
assert(pPrev->member.para.pCell
|
||||
== p->member.para.pCell->member.cell.prev_cell);
|
||||
}
|
||||
}
|
||||
else if (!(p->member.para.nFlags & MEPF_ROWSTART))
|
||||
{
|
||||
assert(!(p->member.para.pFmt->wEffects & (PFE_TABLE|PFE_TABLEROWDELIMITER)));
|
||||
/* ROWSTART must be followed by a cell. */
|
||||
assert(!(p->member.para.nFlags & MEPF_CELL));
|
||||
/* ROWSTART must be followed by a cell. */
|
||||
assert(!(pPrev->member.para.nFlags & MEPF_ROWSTART));
|
||||
}
|
||||
pPrev = p;
|
||||
p = p->member.para.next_para;
|
||||
}
|
||||
} else { /* v1.0 - 3.0 */
|
||||
while (p->type == diParagraph)
|
||||
{
|
||||
assert(!(p->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND|MEPF_CELL)));
|
||||
assert(p->member.para.pFmt->dwMask & PFM_TABLE);
|
||||
assert(!(p->member.para.pFmt->wEffects & PFM_TABLEROWDELIMITER));
|
||||
assert(!p->member.para.pCell);
|
||||
p = p->member.para.next_para;
|
||||
}
|
||||
return;
|
||||
}
|
||||
assert(p->type == diTextEnd);
|
||||
assert(!pPrev->member.para.pCell);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL ME_IsInTable(ME_DisplayItem *pItem)
|
||||
{
|
||||
@ -52,9 +270,6 @@ void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, int nOfs,int *nChars)
|
||||
{
|
||||
ME_Cursor c, c2;
|
||||
ME_DisplayItem *this_para, *end_para;
|
||||
ME_DisplayItem *pRun;
|
||||
int nCharsToBoundary;
|
||||
|
||||
ME_CursorFromCharOfs(editor, nOfs, &c);
|
||||
this_para = ME_GetParagraph(c.pRun);
|
||||
ME_CursorFromCharOfs(editor, nOfs + *nChars, &c2);
|
||||
@ -72,54 +287,111 @@ void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, int nOfs,int *nChars)
|
||||
end_para = end_para->member.para.next_para;
|
||||
}
|
||||
}
|
||||
|
||||
if (this_para->member.para.nCharOfs != nOfs &&
|
||||
this_para->member.para.pFmt->dwMask & PFM_TABLE &&
|
||||
this_para->member.para.pFmt->wEffects & PFE_TABLE)
|
||||
{
|
||||
pRun = c.pRun;
|
||||
/* Find the next tab or end paragraph to use as a delete boundary */
|
||||
while (!(pRun->member.run.nFlags & (MERF_TAB|MERF_ENDPARA)))
|
||||
pRun = ME_FindItemFwd(pRun, diRun);
|
||||
nCharsToBoundary = pRun->member.run.nCharOfs
|
||||
- c.pRun->member.run.nCharOfs
|
||||
- c.nOffset;
|
||||
*nChars = min(*nChars, nCharsToBoundary);
|
||||
} else if (end_para->member.para.pFmt->dwMask & PFM_TABLE &&
|
||||
end_para->member.para.pFmt->wEffects & PFE_TABLE)
|
||||
{
|
||||
if (this_para == end_para)
|
||||
if (!editor->bEmulateVersion10) { /* v4.1 */
|
||||
if (this_para->member.para.pCell != end_para->member.para.pCell ||
|
||||
((this_para->member.para.nFlags|end_para->member.para.nFlags)
|
||||
& (MEPF_ROWSTART|MEPF_ROWEND)))
|
||||
{
|
||||
pRun = c2.pRun;
|
||||
/* Find the previous tab or end paragraph to use as a delete boundary */
|
||||
while (pRun && !(pRun->member.run.nFlags & (MERF_TAB|MERF_ENDPARA)))
|
||||
pRun = ME_FindItemBack(pRun, diRun);
|
||||
if (pRun && pRun->member.run.nFlags & MERF_ENDPARA)
|
||||
while (this_para != end_para)
|
||||
{
|
||||
/* We are in the first cell, and have gone back to the previous
|
||||
* paragraph, so nothing needs to be protected. */
|
||||
pRun = NULL;
|
||||
ME_DisplayItem *next_para = this_para->member.para.next_para;
|
||||
BOOL bTruancateDeletion = FALSE;
|
||||
if (this_para->member.para.nFlags & MEPF_ROWSTART) {
|
||||
/* The following while loop assumes that next_para is MEPF_ROWSTART,
|
||||
* so moving back one paragraph let's it be processed as the start
|
||||
* of the row. */
|
||||
next_para = this_para;
|
||||
this_para = this_para->member.para.prev_para;
|
||||
} else if (next_para->member.para.pCell != this_para->member.para.pCell
|
||||
|| this_para->member.para.nFlags & MEPF_ROWEND)
|
||||
{
|
||||
/* Start of the deletion from after the start of the table row. */
|
||||
bTruancateDeletion = TRUE;
|
||||
}
|
||||
while (!bTruancateDeletion &&
|
||||
next_para->member.para.nFlags & MEPF_ROWSTART)
|
||||
{
|
||||
next_para = ME_GetTableRowEnd(next_para)->member.para.next_para;
|
||||
if (next_para->member.para.nCharOfs > nOfs + *nChars)
|
||||
{
|
||||
/* End of deletion is not past the end of the table row. */
|
||||
next_para = this_para->member.para.next_para;
|
||||
/* Delete the end paragraph preceding the table row if the
|
||||
* preceding table row will be empty. */
|
||||
if (this_para->member.para.nCharOfs >= nOfs)
|
||||
{
|
||||
next_para = next_para->member.para.next_para;
|
||||
}
|
||||
bTruancateDeletion = TRUE;
|
||||
} else {
|
||||
this_para = next_para->member.para.prev_para;
|
||||
}
|
||||
}
|
||||
if (bTruancateDeletion)
|
||||
{
|
||||
ME_Run *end_run = &ME_FindItemBack(next_para, diRun)->member.run;
|
||||
int nCharsNew = (next_para->member.para.nCharOfs - nOfs
|
||||
- end_run->nCR - end_run->nLF);
|
||||
nCharsNew = max(nCharsNew, 0);
|
||||
assert(nCharsNew <= *nChars);
|
||||
*nChars = nCharsNew;
|
||||
break;
|
||||
}
|
||||
this_para = next_para;
|
||||
}
|
||||
} else {
|
||||
/* The deletion starts from before the row, so don't join it with
|
||||
* previous non-empty paragraphs. */
|
||||
pRun = NULL;
|
||||
if (nOfs > this_para->member.para.nCharOfs)
|
||||
pRun = ME_FindItemBack(end_para, diRun);
|
||||
if (!pRun)
|
||||
pRun = ME_FindItemFwd(end_para, diRun);
|
||||
}
|
||||
if (pRun)
|
||||
} else { /* v1.0 - 3.0 */
|
||||
ME_DisplayItem *pRun;
|
||||
int nCharsToBoundary;
|
||||
|
||||
if (this_para->member.para.nCharOfs != nOfs &&
|
||||
this_para->member.para.pFmt->dwMask & PFM_TABLE &&
|
||||
this_para->member.para.pFmt->wEffects & PFE_TABLE)
|
||||
{
|
||||
nCharsToBoundary = ME_GetParagraph(pRun)->member.para.nCharOfs
|
||||
+ pRun->member.run.nCharOfs
|
||||
- nOfs;
|
||||
if (nCharsToBoundary >= 0)
|
||||
*nChars = min(*nChars, nCharsToBoundary);
|
||||
pRun = c.pRun;
|
||||
/* Find the next tab or end paragraph to use as a delete boundary */
|
||||
while (!(pRun->member.run.nFlags & (MERF_TAB|MERF_ENDPARA)))
|
||||
pRun = ME_FindItemFwd(pRun, diRun);
|
||||
nCharsToBoundary = pRun->member.run.nCharOfs
|
||||
- c.pRun->member.run.nCharOfs
|
||||
- c.nOffset;
|
||||
*nChars = min(*nChars, nCharsToBoundary);
|
||||
} else if (end_para->member.para.pFmt->dwMask & PFM_TABLE &&
|
||||
end_para->member.para.pFmt->wEffects & PFE_TABLE)
|
||||
{
|
||||
if (this_para == end_para)
|
||||
{
|
||||
pRun = c2.pRun;
|
||||
/* Find the previous tab or end paragraph to use as a delete boundary */
|
||||
while (pRun && !(pRun->member.run.nFlags & (MERF_TAB|MERF_ENDPARA)))
|
||||
pRun = ME_FindItemBack(pRun, diRun);
|
||||
if (pRun && pRun->member.run.nFlags & MERF_ENDPARA)
|
||||
{
|
||||
/* We are in the first cell, and have gone back to the previous
|
||||
* paragraph, so nothing needs to be protected. */
|
||||
pRun = NULL;
|
||||
}
|
||||
} else {
|
||||
/* The deletion starts from before the row, so don't join it with
|
||||
* previous non-empty paragraphs. */
|
||||
pRun = NULL;
|
||||
if (nOfs > this_para->member.para.nCharOfs)
|
||||
pRun = ME_FindItemBack(end_para, diRun);
|
||||
if (!pRun)
|
||||
pRun = ME_FindItemFwd(end_para, diRun);
|
||||
}
|
||||
if (pRun)
|
||||
{
|
||||
nCharsToBoundary = ME_GetParagraph(pRun)->member.para.nCharOfs
|
||||
+ pRun->member.run.nCharOfs
|
||||
- nOfs;
|
||||
if (nCharsToBoundary >= 0)
|
||||
*nChars = min(*nChars, nCharsToBoundary);
|
||||
}
|
||||
}
|
||||
if (*nChars < 0)
|
||||
nChars = 0;
|
||||
}
|
||||
if (*nChars < 0)
|
||||
nChars = 0;
|
||||
}
|
||||
|
||||
static ME_DisplayItem* ME_AppendTableRow(ME_TextEditor *editor,
|
||||
@ -131,18 +403,42 @@ static ME_DisplayItem* ME_AppendTableRow(ME_TextEditor *editor,
|
||||
int i;
|
||||
|
||||
assert(table_row);
|
||||
run = ME_FindItemBack(table_row->member.para.next_para, diRun);
|
||||
pFmt = table_row->member.para.pFmt;
|
||||
assert(pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE);
|
||||
editor->pCursors[0].pRun = run;
|
||||
editor->pCursors[0].nOffset = 0;
|
||||
editor->pCursors[1] = editor->pCursors[0];
|
||||
ME_InsertTextFromCursor(editor, 0, &endl, 1, run->member.run.style);
|
||||
run = editor->pCursors[0].pRun;
|
||||
for (i = 0; i < pFmt->cTabCount; i++) {
|
||||
ME_InsertTextFromCursor(editor, 0, &tab, 1, run->member.run.style);
|
||||
if (!editor->bEmulateVersion10) { /* v4.1 */
|
||||
ME_DisplayItem *insertedCell, *para, *cell;
|
||||
cell = ME_FindItemFwd(table_row, diCell);
|
||||
run = ME_GetTableRowEnd(table_row)->member.para.next_para;
|
||||
run = ME_FindItemFwd(run, diRun);
|
||||
editor->pCursors[0].pRun = run;
|
||||
editor->pCursors[0].nOffset = 0;
|
||||
editor->pCursors[1] = editor->pCursors[0];
|
||||
para = ME_InsertTableRowStartFromCursor(editor);
|
||||
insertedCell = ME_FindItemFwd(para, diCell);
|
||||
/* Copy cell properties */
|
||||
insertedCell->member.cell.nRightBoundary = cell->member.cell.nRightBoundary;
|
||||
while (cell->member.cell.next_cell) {
|
||||
cell = cell->member.cell.next_cell;
|
||||
para = ME_InsertTableCellFromCursor(editor);
|
||||
insertedCell = ME_FindItemBack(para, diCell);
|
||||
/* Copy cell properties */
|
||||
insertedCell->member.cell.nRightBoundary = cell->member.cell.nRightBoundary;
|
||||
};
|
||||
ME_InsertTableRowEndFromCursor(editor);
|
||||
/* return the table row start for the inserted paragraph */
|
||||
return ME_FindItemFwd(cell, diParagraph)->member.para.next_para;
|
||||
} else { /* v1.0 - 3.0 */
|
||||
run = ME_FindItemBack(table_row->member.para.next_para, diRun);
|
||||
pFmt = table_row->member.para.pFmt;
|
||||
assert(pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE);
|
||||
editor->pCursors[0].pRun = run;
|
||||
editor->pCursors[0].nOffset = 0;
|
||||
editor->pCursors[1] = editor->pCursors[0];
|
||||
ME_InsertTextFromCursor(editor, 0, &endl, 1, run->member.run.style);
|
||||
run = editor->pCursors[0].pRun;
|
||||
for (i = 0; i < pFmt->cTabCount; i++) {
|
||||
ME_InsertTextFromCursor(editor, 0, &tab, 1, run->member.run.style);
|
||||
}
|
||||
return table_row->member.para.next_para;
|
||||
}
|
||||
return table_row->member.para.next_para;
|
||||
}
|
||||
|
||||
/* Selects the next table cell or appends a new table row if at end of table */
|
||||
@ -154,43 +450,88 @@ static void ME_SelectOrInsertNextCell(ME_TextEditor *editor,
|
||||
|
||||
assert(run && run->type == diRun);
|
||||
assert(ME_IsInTable(run));
|
||||
if (run->member.run.nFlags & MERF_ENDPARA &&
|
||||
ME_IsInTable(ME_FindItemFwd(run, diParagraphOrEnd)))
|
||||
{
|
||||
run = ME_FindItemFwd(run, diRun);
|
||||
assert(run);
|
||||
}
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
while (!(run->member.run.nFlags & MERF_TAB))
|
||||
if (!editor->bEmulateVersion10) { /* v4.1 */
|
||||
ME_DisplayItem *cell;
|
||||
/* Get the initial cell */
|
||||
if (para->member.para.nFlags & MEPF_ROWSTART) {
|
||||
cell = para->member.para.next_para->member.para.pCell;
|
||||
} else if (para->member.para.nFlags & MEPF_ROWEND) {
|
||||
cell = para->member.para.prev_para->member.para.pCell;
|
||||
} else {
|
||||
cell = para->member.para.pCell;
|
||||
}
|
||||
assert(cell);
|
||||
/* Get the next cell. */
|
||||
if (cell->member.cell.next_cell &&
|
||||
cell->member.cell.next_cell->member.cell.next_cell)
|
||||
{
|
||||
run = ME_FindItemFwd(run, diRunOrParagraphOrEnd);
|
||||
if (run->type != diRun)
|
||||
{
|
||||
para = run;
|
||||
if (ME_IsInTable(para))
|
||||
{
|
||||
run = ME_FindItemFwd(para, diRun);
|
||||
assert(run);
|
||||
editor->pCursors[0].pRun = run;
|
||||
editor->pCursors[0].nOffset = 0;
|
||||
i = 1;
|
||||
} else {
|
||||
/* Insert table row */
|
||||
para = ME_AppendTableRow(editor, para->member.para.prev_para);
|
||||
/* Put cursor at the start of the new table row */
|
||||
editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun);
|
||||
editor->pCursors[0].nOffset = 0;
|
||||
editor->pCursors[1] = editor->pCursors[0];
|
||||
ME_WrapMarkedParagraphs(editor);
|
||||
return;
|
||||
}
|
||||
cell = cell->member.cell.next_cell;
|
||||
} else {
|
||||
para = ME_GetTableRowEnd(ME_FindItemFwd(cell, diParagraph));
|
||||
para = para->member.para.next_para;
|
||||
assert(para);
|
||||
if (para->member.para.nFlags & MEPF_ROWSTART) {
|
||||
cell = para->member.para.next_para->member.para.pCell;
|
||||
} else {
|
||||
/* Insert row */
|
||||
para = para->member.para.prev_para;
|
||||
para = ME_AppendTableRow(editor, ME_GetTableRowStart(para));
|
||||
/* Put cursor at the start of the new table row */
|
||||
para = para->member.para.next_para;
|
||||
editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun);
|
||||
editor->pCursors[0].nOffset = 0;
|
||||
editor->pCursors[1] = editor->pCursors[0];
|
||||
ME_WrapMarkedParagraphs(editor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (i == 0)
|
||||
/* Select cell */
|
||||
editor->pCursors[1].pRun = ME_FindItemFwd(cell, diRun);
|
||||
editor->pCursors[1].nOffset = 0;
|
||||
assert(editor->pCursors[0].pRun);
|
||||
cell = cell->member.cell.next_cell;
|
||||
editor->pCursors[0].pRun = ME_FindItemBack(cell, diRun);
|
||||
editor->pCursors[0].nOffset = 0;
|
||||
assert(editor->pCursors[1].pRun);
|
||||
} else { /* v1.0 - 3.0 */
|
||||
if (run->member.run.nFlags & MERF_ENDPARA &&
|
||||
ME_IsInTable(ME_FindItemFwd(run, diParagraphOrEnd)))
|
||||
{
|
||||
run = ME_FindItemFwd(run, diRun);
|
||||
editor->pCursors[i].pRun = run;
|
||||
editor->pCursors[i].nOffset = 0;
|
||||
assert(run);
|
||||
}
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
while (!(run->member.run.nFlags & MERF_TAB))
|
||||
{
|
||||
run = ME_FindItemFwd(run, diRunOrParagraphOrEnd);
|
||||
if (run->type != diRun)
|
||||
{
|
||||
para = run;
|
||||
if (ME_IsInTable(para))
|
||||
{
|
||||
run = ME_FindItemFwd(para, diRun);
|
||||
assert(run);
|
||||
editor->pCursors[0].pRun = run;
|
||||
editor->pCursors[0].nOffset = 0;
|
||||
i = 1;
|
||||
} else {
|
||||
/* Insert table row */
|
||||
para = ME_AppendTableRow(editor, para->member.para.prev_para);
|
||||
/* Put cursor at the start of the new table row */
|
||||
editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun);
|
||||
editor->pCursors[0].nOffset = 0;
|
||||
editor->pCursors[1] = editor->pCursors[0];
|
||||
ME_WrapMarkedParagraphs(editor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i == 0)
|
||||
run = ME_FindItemFwd(run, diRun);
|
||||
editor->pCursors[i].pRun = run;
|
||||
editor->pCursors[i].nOffset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,18 +554,25 @@ void ME_TabPressedInTable(ME_TextEditor *editor, BOOL bSelectedRow)
|
||||
toCursor = editor->pCursors[0];
|
||||
}
|
||||
}
|
||||
if (!ME_IsInTable(fromCursor.pRun))
|
||||
if (!editor->bEmulateVersion10) /* v4.1 */
|
||||
{
|
||||
editor->pCursors[0] = fromCursor;
|
||||
editor->pCursors[1] = fromCursor;
|
||||
/* FIXME: For some reason the caret is shown at the start of the
|
||||
* previous paragraph in v1.0 to v3.0, and bCaretAtEnd only works
|
||||
* within the paragraph for wrapped lines. */
|
||||
if (ME_FindItemBack(fromCursor.pRun, diRun))
|
||||
editor->bCaretAtEnd = TRUE;
|
||||
} else {
|
||||
if (bSelectedRow || !ME_IsInTable(toCursor.pRun))
|
||||
if (!ME_IsInTable(toCursor.pRun))
|
||||
{
|
||||
editor->pCursors[0] = toCursor;
|
||||
editor->pCursors[1] = toCursor;
|
||||
} else {
|
||||
ME_SelectOrInsertNextCell(editor, toCursor.pRun);
|
||||
}
|
||||
} else { /* v1.0 - 3.0 */
|
||||
if (!ME_IsInTable(fromCursor.pRun)) {
|
||||
editor->pCursors[0] = fromCursor;
|
||||
editor->pCursors[1] = fromCursor;
|
||||
/* FIXME: For some reason the caret is shown at the start of the
|
||||
* previous paragraph in v1.0 to v3.0, and bCaretAtEnd only works
|
||||
* within the paragraph for wrapped lines. */
|
||||
if (ME_FindItemBack(fromCursor.pRun, diRun))
|
||||
editor->bCaretAtEnd = TRUE;
|
||||
} else if ((bSelectedRow || !ME_IsInTable(toCursor.pRun))) {
|
||||
ME_SelectOrInsertNextCell(editor, fromCursor.pRun);
|
||||
} else {
|
||||
if (ME_IsSelection(editor) && !toCursor.nOffset)
|
||||
|
@ -89,10 +89,17 @@ ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, const ME_Disp
|
||||
case diUndoJoinParagraphs:
|
||||
break;
|
||||
case diUndoSplitParagraph:
|
||||
{
|
||||
ME_DisplayItem *prev_para = pdi->member.para.prev_para;
|
||||
assert(pdi->member.para.pFmt->cbSize == sizeof(PARAFORMAT2));
|
||||
pItem->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2);
|
||||
pItem->member.para.pFmt->cbSize = sizeof(PARAFORMAT2);
|
||||
pItem->member.para.pFmt->dwMask = 0;
|
||||
*pItem->member.para.pFmt = *pdi->member.para.pFmt;
|
||||
pItem->member.para.nFlags = prev_para->member.para.nFlags & ~MEPF_CELL;
|
||||
pItem->member.para.pCell = NULL;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0 == "AddUndoItem, unsupported item type");
|
||||
return NULL;
|
||||
@ -314,16 +321,35 @@ static void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem)
|
||||
case diUndoSplitParagraph:
|
||||
{
|
||||
ME_Cursor tmp;
|
||||
ME_DisplayItem *new_para;
|
||||
ME_DisplayItem *this_para, *new_para;
|
||||
BOOL bFixRowStart;
|
||||
int paraFlags = pItem->member.para.nFlags & (MEPF_ROWSTART|MEPF_CELL|MEPF_ROWEND);
|
||||
ME_CursorFromCharOfs(editor, pUItem->nStart, &tmp);
|
||||
if (tmp.nOffset)
|
||||
tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset);
|
||||
assert(pUItem->nCR >= 0);
|
||||
assert(pUItem->nLF >= 0);
|
||||
this_para = ME_GetParagraph(tmp.pRun);
|
||||
bFixRowStart = this_para->member.para.nFlags & MEPF_ROWSTART;
|
||||
if (bFixRowStart)
|
||||
{
|
||||
/* Re-insert the paragraph before the table, making sure the nFlag value
|
||||
* is correct. */
|
||||
this_para->member.para.nFlags &= ~MEPF_ROWSTART;
|
||||
}
|
||||
new_para = ME_SplitParagraph(editor, tmp.pRun, tmp.pRun->member.run.style,
|
||||
pUItem->nCR, pUItem->nLF);
|
||||
pUItem->nCR, pUItem->nLF, paraFlags);
|
||||
if (bFixRowStart)
|
||||
new_para->member.para.nFlags |= MEPF_ROWSTART;
|
||||
assert(pItem->member.para.pFmt->cbSize == sizeof(PARAFORMAT2));
|
||||
*new_para->member.para.pFmt = *pItem->member.para.pFmt;
|
||||
if (pItem->member.para.pCell)
|
||||
{
|
||||
ME_DisplayItem *pItemCell, *pCell;
|
||||
pItemCell = pItem->member.para.pCell;
|
||||
pCell = new_para->member.para.pCell;
|
||||
pCell->member.cell.nRightBoundary = pItemCell->member.cell.nRightBoundary;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -361,6 +387,7 @@ BOOL ME_Undo(ME_TextEditor *editor) {
|
||||
if (p)
|
||||
p->prev = NULL;
|
||||
ME_AddUndoItem(editor, diUndoEndTransaction, NULL);
|
||||
ME_CheckTablesForCorruption(editor);
|
||||
editor->nUndoStackSize--;
|
||||
editor->nUndoMode = nMode;
|
||||
ME_UpdateRepaint(editor);
|
||||
@ -396,6 +423,7 @@ BOOL ME_Redo(ME_TextEditor *editor) {
|
||||
if (p)
|
||||
p->prev = NULL;
|
||||
ME_AddUndoItem(editor, diUndoEndTransaction, NULL);
|
||||
ME_CheckTablesForCorruption(editor);
|
||||
editor->nUndoMode = nMode;
|
||||
ME_UpdateRepaint(editor);
|
||||
return TRUE;
|
||||
|
@ -42,17 +42,37 @@ static ME_DisplayItem *ME_MakeRow(int height, int baseline, int width)
|
||||
return item;
|
||||
}
|
||||
|
||||
static void ME_BeginRow(ME_WrapContext *wc)
|
||||
static void ME_BeginRow(ME_WrapContext *wc, ME_DisplayItem *para)
|
||||
{
|
||||
assert(para && para->type == diParagraph);
|
||||
wc->pRowStart = NULL;
|
||||
wc->bOverflown = FALSE;
|
||||
wc->pLastSplittableRun = NULL;
|
||||
if (wc->context->editor->bWordWrap)
|
||||
wc->nAvailWidth = wc->context->rcView.right - wc->context->rcView.left -
|
||||
(wc->nRow ? wc->nLeftMargin : wc->nFirstMargin) - wc->nRightMargin;
|
||||
else
|
||||
if (para->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND)) {
|
||||
wc->nAvailWidth = 0;
|
||||
if (para->member.para.nFlags & MEPF_ROWEND)
|
||||
{
|
||||
ME_Cell *cell = &ME_FindItemBack(para, diCell)->member.cell;
|
||||
cell->nWidth = 0;
|
||||
}
|
||||
} else if (para->member.para.pCell) {
|
||||
ME_Cell *cell = ¶->member.para.pCell->member.cell;
|
||||
int width;
|
||||
|
||||
width = cell->nRightBoundary;
|
||||
if (cell->prev_cell)
|
||||
width -= cell->prev_cell->member.cell.nRightBoundary;
|
||||
cell->nWidth = max(ME_twips2pointsX(wc->context, width), 0);
|
||||
|
||||
wc->nAvailWidth = cell->nWidth
|
||||
- (wc->nRow ? wc->nLeftMargin : wc->nFirstMargin) - wc->nRightMargin;
|
||||
} else if (wc->context->editor->bWordWrap) {
|
||||
wc->nAvailWidth = wc->context->rcView.right - wc->context->rcView.left
|
||||
- (wc->nRow ? wc->nLeftMargin : wc->nFirstMargin) - wc->nRightMargin;
|
||||
} else {
|
||||
wc->nAvailWidth = ~0u >> 1;
|
||||
wc->pt.x = 0;
|
||||
}
|
||||
wc->pt.x = wc->context->pt.x;
|
||||
}
|
||||
|
||||
static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd)
|
||||
@ -100,7 +120,7 @@ static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd)
|
||||
}
|
||||
|
||||
row = ME_MakeRow(ascent+descent, ascent, width);
|
||||
row->member.row.nYPos = wc->pt.y;
|
||||
row->member.row.pt = wc->pt;
|
||||
row->member.row.nLMargin = (!wc->nRow ? wc->nFirstMargin : wc->nLeftMargin);
|
||||
row->member.row.nRMargin = wc->nRightMargin;
|
||||
assert(para->member.para.pFmt->dwMask & PFM_ALIGNMENT);
|
||||
@ -118,7 +138,7 @@ static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd)
|
||||
ME_InsertBefore(wc->pRowStart, row);
|
||||
wc->nRow++;
|
||||
wc->pt.y += ascent+descent;
|
||||
ME_BeginRow(wc);
|
||||
ME_BeginRow(wc, para);
|
||||
}
|
||||
|
||||
static void ME_WrapEndParagraph(ME_WrapContext *wc, ME_DisplayItem *p)
|
||||
@ -326,9 +346,9 @@ static ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
|
||||
}
|
||||
|
||||
/* will current run fit? */
|
||||
if (wc->pt.x + run->nWidth > wc->nAvailWidth)
|
||||
if (wc->pt.x + run->nWidth > wc->context->pt.x + wc->nAvailWidth)
|
||||
{
|
||||
int loc = wc->nAvailWidth - wc->pt.x;
|
||||
int loc = wc->context->pt.x + wc->nAvailWidth - wc->pt.x;
|
||||
/* total white run ? */
|
||||
if (run->nFlags & MERF_WHITESPACE) {
|
||||
/* let the overflow logic handle it */
|
||||
@ -421,7 +441,6 @@ static void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp, DWORD begino
|
||||
wc.nLeftMargin = wc.nFirstMargin + ME_twips2pointsX(c, tp->member.para.pFmt->dxOffset);
|
||||
wc.nRightMargin = ME_twips2pointsX(c, tp->member.para.pFmt->dxRightIndent);
|
||||
wc.nRow = 0;
|
||||
wc.pt.x = 0;
|
||||
wc.pt.y = 0;
|
||||
if (tp->member.para.pFmt->dwMask & PFM_SPACEBEFORE)
|
||||
wc.pt.y += ME_twips2pointsY(c, tp->member.para.pFmt->dySpaceBefore);
|
||||
@ -440,7 +459,7 @@ static void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp, DWORD begino
|
||||
|
||||
linespace = ME_GetParaLineSpace(c, &tp->member.para);
|
||||
|
||||
ME_BeginRow(&wc);
|
||||
ME_BeginRow(&wc, tp);
|
||||
for (p = tp->next; p!=tp->member.para.next_para; ) {
|
||||
assert(p->type != diStartRow);
|
||||
if (p->type == diRun) {
|
||||
@ -515,11 +534,11 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
|
||||
BOOL bRedraw = FALSE;
|
||||
|
||||
assert(item->type == diParagraph);
|
||||
editor->nHeight = max(editor->nHeight, item->member.para.nYPos);
|
||||
editor->nHeight = max(editor->nHeight, item->member.para.pt.y);
|
||||
if ((item->member.para.nFlags & MEPF_REWRAP)
|
||||
|| (item->member.para.nYPos != c.pt.y))
|
||||
|| (item->member.para.pt.y != c.pt.y))
|
||||
bRedraw = TRUE;
|
||||
item->member.para.nYPos = c.pt.y;
|
||||
item->member.para.pt = c.pt;
|
||||
|
||||
ME_WrapTextParagraph(&c, item, editor->selofs);
|
||||
|
||||
@ -532,24 +551,90 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
|
||||
|
||||
bModified = bModified | bRedraw;
|
||||
|
||||
yLastPos = c.pt.y;
|
||||
c.pt.y += item->member.para.nHeight;
|
||||
yLastPos = max(yLastPos, c.pt.y);
|
||||
|
||||
if (item->member.para.nFlags & MEPF_ROWSTART)
|
||||
{
|
||||
ME_DisplayItem *cell = ME_FindItemFwd(item, diCell);
|
||||
cell->member.cell.pt = c.pt;
|
||||
}
|
||||
else if (item->member.para.nFlags & MEPF_ROWEND)
|
||||
{
|
||||
/* Set all the cells to the height of the largest cell */
|
||||
ME_DisplayItem *startRowPara;
|
||||
int prevHeight, nHeight;
|
||||
ME_DisplayItem *cell = ME_FindItemBack(item, diCell);
|
||||
prevHeight = cell->member.cell.nHeight;
|
||||
nHeight = cell->member.cell.prev_cell->member.cell.nHeight;
|
||||
cell->member.cell.nHeight = nHeight;
|
||||
item->member.para.nHeight = nHeight;
|
||||
cell = cell->member.cell.prev_cell;
|
||||
while (cell->member.cell.prev_cell)
|
||||
{
|
||||
cell = cell->member.cell.prev_cell;
|
||||
cell->member.cell.nHeight = nHeight;
|
||||
}
|
||||
/* Also set the height of the start row paragraph */
|
||||
startRowPara = ME_FindItemBack(cell, diParagraph);
|
||||
startRowPara->member.para.nHeight = nHeight;
|
||||
c.pt.x = startRowPara->member.para.pt.x;
|
||||
c.pt.y = cell->member.cell.pt.y + nHeight;
|
||||
if (prevHeight < nHeight)
|
||||
{
|
||||
/* The height of the cells has grown, so invalidate the bottom of
|
||||
* the cells. */
|
||||
item->member.para.nFlags |= MEPF_REPAINT;
|
||||
cell = ME_FindItemBack(item, diCell);
|
||||
while (cell) {
|
||||
ME_FindItemBack(cell, diParagraph)->member.para.nFlags |= MEPF_REPAINT;
|
||||
cell = cell->member.cell.prev_cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (item->member.para.pCell &&
|
||||
item->member.para.pCell != item->member.para.next_para->member.para.pCell)
|
||||
{
|
||||
/* The next paragraph is in the next cell in the table row. */
|
||||
ME_Cell *cell = &item->member.para.pCell->member.cell;
|
||||
cell->nHeight = c.pt.y + item->member.para.nHeight - cell->pt.y;
|
||||
|
||||
/* Propagate the largest height to the end so that it can be easily
|
||||
* sent back to all the cells at the end of the row. */
|
||||
if (cell->prev_cell)
|
||||
cell->nHeight = max(cell->nHeight, cell->prev_cell->member.cell.nHeight);
|
||||
|
||||
c.pt.x = cell->pt.x + cell->nWidth;
|
||||
c.pt.y = cell->pt.y;
|
||||
cell->next_cell->member.cell.pt = c.pt;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item->member.para.pCell) {
|
||||
/* Next paragraph in the same cell. */
|
||||
c.pt.x = item->member.para.pCell->member.cell.pt.x;
|
||||
} else {
|
||||
/* Normal paragraph */
|
||||
c.pt.x = 0;
|
||||
}
|
||||
c.pt.y += item->member.para.nHeight;
|
||||
}
|
||||
item = item->member.para.next_para;
|
||||
}
|
||||
editor->sizeWindow.cx = c.rcView.right-c.rcView.left;
|
||||
editor->sizeWindow.cy = c.rcView.bottom-c.rcView.top;
|
||||
|
||||
editor->nTotalLength = c.pt.y;
|
||||
editor->pBuffer->pLast->member.para.nYPos = yLastPos;
|
||||
editor->pBuffer->pLast->member.para.pt.x = 0;
|
||||
editor->pBuffer->pLast->member.para.pt.y = yLastPos;
|
||||
|
||||
ME_DestroyContext(&c, editor->hWnd);
|
||||
|
||||
/* Each paragraph may contain multiple rows, which should be scrollable, even
|
||||
if the containing paragraph has nYPos == 0 */
|
||||
if the containing paragraph has pt.y == 0 */
|
||||
item = editor->pBuffer->pFirst;
|
||||
while ((item = ME_FindItemFwd(item, diStartRow)) != NULL) {
|
||||
assert(item->type == diStartRow);
|
||||
editor->nHeight = max(editor->nHeight, item->member.row.nYPos);
|
||||
editor->nHeight = max(editor->nHeight, item->member.row.pt.y);
|
||||
}
|
||||
|
||||
if (bModified || editor->nTotalLength < editor->nLastTotalLength)
|
||||
@ -569,8 +654,8 @@ void ME_InvalidateMarkedParagraphs(ME_TextEditor *editor) {
|
||||
ME_DisplayItem *item = editor->pBuffer->pFirst;
|
||||
while(item != editor->pBuffer->pLast) {
|
||||
if (item->member.para.nFlags & MEPF_REPAINT) {
|
||||
rc.top = item->member.para.nYPos - ofs;
|
||||
rc.bottom = item->member.para.nYPos + item->member.para.nHeight - ofs;
|
||||
rc.top = item->member.para.pt.y - ofs;
|
||||
rc.bottom = item->member.para.pt.y + item->member.para.nHeight - ofs;
|
||||
InvalidateRect(editor->hWnd, &rc, TRUE);
|
||||
}
|
||||
item = item->member.para.next_para;
|
||||
|
@ -41,6 +41,7 @@ ME_StreamOutInit(ME_TextEditor *editor, EDITSTREAM *stream)
|
||||
pStream->written = 0;
|
||||
pStream->nFontTblLen = 0;
|
||||
pStream->nColorTblLen = 1;
|
||||
pStream->nNestingLevel = 0;
|
||||
return pStream;
|
||||
}
|
||||
|
||||
@ -284,28 +285,43 @@ ME_StreamOutRTFFontAndColorTbl(ME_OutStream *pStream, ME_DisplayItem *pFirstRun,
|
||||
}
|
||||
|
||||
static BOOL
|
||||
ME_StreamOutRTFTableProps(ME_OutStream *pStream, const ME_DisplayItem *para)
|
||||
ME_StreamOutRTFTableProps(ME_TextEditor *editor, ME_OutStream *pStream,
|
||||
const ME_DisplayItem *para)
|
||||
{
|
||||
PARAFORMAT2 *pFmt;
|
||||
ME_DisplayItem *cell;
|
||||
char props[STREAMOUT_BUFFER_SIZE] = "";
|
||||
int i;
|
||||
|
||||
if (!ME_StreamOutPrint(pStream, "\\trowd"))
|
||||
return FALSE;
|
||||
pFmt = para->member.para.pFmt;
|
||||
if (!editor->bEmulateVersion10) { /* v4.1 */
|
||||
assert(para->member.para.nFlags & MEPF_ROWSTART);
|
||||
cell = para->member.para.next_para->member.para.pCell;
|
||||
assert(cell);
|
||||
do {
|
||||
sprintf(props, "\\cellx%d", cell->member.cell.nRightBoundary);
|
||||
if (!ME_StreamOutPrint(pStream, props))
|
||||
return FALSE;
|
||||
cell = cell->member.cell.next_cell;
|
||||
} while (cell->member.cell.next_cell);
|
||||
} else { /* v1.0 - 3.0 */
|
||||
PARAFORMAT2 *pFmt = para->member.para.pFmt;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pFmt->cTabCount; i++)
|
||||
{
|
||||
sprintf(props, "\\cellx%d", pFmt->rgxTabs[i] & 0x00FFFFFF);
|
||||
if (!ME_StreamOutPrint(pStream, props))
|
||||
return FALSE;
|
||||
assert(!(para->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND|MEPF_CELL)));
|
||||
for (i = 0; i < pFmt->cTabCount; i++)
|
||||
{
|
||||
sprintf(props, "\\cellx%d", pFmt->rgxTabs[i] & 0x00FFFFFF);
|
||||
if (!ME_StreamOutPrint(pStream, props))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
props[0] = '\0';
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
ME_StreamOutRTFParaProps(ME_OutStream *pStream, const ME_DisplayItem *para)
|
||||
ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_OutStream *pStream,
|
||||
const ME_DisplayItem *para)
|
||||
{
|
||||
PARAFORMAT2 *fmt = para->member.para.pFmt;
|
||||
char props[STREAMOUT_BUFFER_SIZE] = "";
|
||||
@ -315,8 +331,13 @@ ME_StreamOutRTFParaProps(ME_OutStream *pStream, const ME_DisplayItem *para)
|
||||
if (!ME_StreamOutPrint(pStream, "\\pard"))
|
||||
return FALSE;
|
||||
|
||||
if (fmt->dwMask & PFM_TABLE && fmt->wEffects & PFE_TABLE)
|
||||
strcat(props, "\\intbl");
|
||||
if (!editor->bEmulateVersion10) { /* v4.1 */
|
||||
if (pStream->nNestingLevel > 0)
|
||||
strcat(props, "\\intbl");
|
||||
} else { /* v1.0 - 3.0 */
|
||||
if (fmt->dwMask & PFM_TABLE && fmt->wEffects & PFE_TABLE)
|
||||
strcat(props, "\\intbl");
|
||||
}
|
||||
|
||||
/* TODO: PFM_BORDER. M$ does not emit any keywords for these properties, and
|
||||
* when streaming border keywords in, PFM_BORDER is set, but wBorder field is
|
||||
@ -683,7 +704,7 @@ ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int nC
|
||||
|
||||
/* TODO: section formatting properties */
|
||||
|
||||
if (!ME_StreamOutRTFParaProps(pStream, ME_GetParagraph(p)))
|
||||
if (!ME_StreamOutRTFParaProps(editor, pStream, ME_GetParagraph(p)))
|
||||
return FALSE;
|
||||
|
||||
while(1)
|
||||
@ -691,14 +712,28 @@ ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int nC
|
||||
switch(p->type)
|
||||
{
|
||||
case diParagraph:
|
||||
if (p->member.para.pFmt->dwMask & PFM_TABLE &&
|
||||
p->member.para.pFmt->wEffects & PFE_TABLE)
|
||||
{
|
||||
if (!ME_StreamOutRTFTableProps(pStream, p))
|
||||
if (!editor->bEmulateVersion10) { /* v4.1 */
|
||||
if (p->member.para.nFlags & MEPF_ROWSTART) {
|
||||
pStream->nNestingLevel++;
|
||||
if (!ME_StreamOutRTFTableProps(editor, pStream, p))
|
||||
return FALSE;
|
||||
} else if (p->member.para.nFlags & MEPF_ROWEND) {
|
||||
pStream->nNestingLevel--;
|
||||
if (!ME_StreamOutPrint(pStream, "\\row \r\n"))
|
||||
return FALSE;
|
||||
} else if (!ME_StreamOutRTFParaProps(editor, pStream, p)) {
|
||||
return FALSE;
|
||||
}
|
||||
} else { /* v1.0 - 3.0 */
|
||||
if (p->member.para.pFmt->dwMask & PFM_TABLE &&
|
||||
p->member.para.pFmt->wEffects & PFE_TABLE)
|
||||
{
|
||||
if (!ME_StreamOutRTFTableProps(editor, pStream, p))
|
||||
return FALSE;
|
||||
}
|
||||
if (!ME_StreamOutRTFParaProps(editor, pStream, p))
|
||||
return FALSE;
|
||||
}
|
||||
if (!ME_StreamOutRTFParaProps(pStream, p))
|
||||
return FALSE;
|
||||
pPara = p;
|
||||
break;
|
||||
case diRun:
|
||||
@ -706,10 +741,13 @@ ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int nC
|
||||
break;
|
||||
TRACE("flags %xh\n", p->member.run.nFlags);
|
||||
/* TODO: emit embedded objects */
|
||||
if (pPara->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND))
|
||||
break;
|
||||
if (p->member.run.nFlags & MERF_GRAPHICS) {
|
||||
FIXME("embedded objects are not handled\n");
|
||||
} else if (p->member.run.nFlags & MERF_TAB) {
|
||||
if (pPara->member.para.pFmt->dwMask & PFM_TABLE &&
|
||||
if (editor->bEmulateVersion10 && /* v1.0 - 3.0 */
|
||||
pPara->member.para.pFmt->dwMask & PFM_TABLE &&
|
||||
pPara->member.para.pFmt->wEffects & PFE_TABLE)
|
||||
{
|
||||
if (!ME_StreamOutPrint(pStream, "\\cell "))
|
||||
@ -718,9 +756,14 @@ ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int nC
|
||||
if (!ME_StreamOutPrint(pStream, "\\tab "))
|
||||
return FALSE;
|
||||
}
|
||||
} else if (p->member.run.nFlags & MERF_ENDCELL) {
|
||||
if (!ME_StreamOutPrint(pStream, "\\cell "))
|
||||
return FALSE;
|
||||
nChars--;
|
||||
} else if (p->member.run.nFlags & MERF_ENDPARA) {
|
||||
if (pPara->member.para.pFmt->dwMask & PFM_TABLE
|
||||
&& pPara->member.para.pFmt->wEffects & PFE_TABLE)
|
||||
if (pPara->member.para.pFmt->dwMask & PFM_TABLE &&
|
||||
pPara->member.para.pFmt->wEffects & PFE_TABLE &&
|
||||
!(pPara->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND|MEPF_CELL)))
|
||||
{
|
||||
if (!ME_StreamOutPrint(pStream, "\\row \r\n"))
|
||||
return FALSE;
|
||||
|
Loading…
x
Reference in New Issue
Block a user