Commit 300db376 authored by Dylan Smith's avatar Dylan Smith Committed by Alexandre Julliard

richedit: Each cell can contain multiple paragraphs in msftedit.

parent bc61a637
......@@ -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 = &para->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 = &para->next_para->member.para.pCell->member.cell;
rc.right = cell->pt.x;
} else if (para->nFlags & MEPF_ROWEND) {
ME_Cell *cell = &para->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 = &para->next_para->member.para.pCell->member.cell;
rc.bottom = y + cell->nHeight;
} else if (para->nFlags & MEPF_ROWEND) {
ME_Cell *cell = &para->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;
......
......@@ -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 = &para->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;
for (i = 0; i < pFmt->cTabCount; i++)
{
sprintf(props, "\\cellx%d", pFmt->rgxTabs[i] & 0x00FFFFFF);
if (!ME_StreamOutPrint(pStream, props))
return FALSE;
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;
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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment