diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c index 2b0703f..9fc11a5 100644 --- a/dlls/riched20/editor.c +++ b/dlls/riched20/editor.c @@ -451,6 +451,10 @@ static void ME_RTFParAttrHook(RTF_Info *info) switch(info->rtfMinor) { case rtfParDef: /* restores default paragraph attributes */ + if (!info->editor->bEmulateVersion10) /* v4.1 */ + info->borderType = RTFBorderParaLeft; + else /* v1.0 - 3.0 */ + info->borderType = RTFBorderParaTop; fmt.dwMask = PFM_ALIGNMENT | PFM_BORDER | PFM_LINESPACING | PFM_TABSTOPS | PFM_OFFSET | PFM_RIGHTINDENT | PFM_SPACEAFTER | PFM_SPACEBEFORE | PFM_STARTINDENT; @@ -656,6 +660,7 @@ static void ME_RTFParAttrHook(RTF_Info *info) fmt.wNumberingStart = info->rtfParam; break; case rtfBorderLeft: + info->borderType = RTFBorderParaLeft; ME_GetSelectionParaFormat(info->editor, &fmt); if (!(fmt.dwMask & PFM_BORDER)) { @@ -667,6 +672,7 @@ static void ME_RTFParAttrHook(RTF_Info *info) fmt.dwMask = PFM_BORDER; break; case rtfBorderRight: + info->borderType = RTFBorderParaRight; ME_GetSelectionParaFormat(info->editor, &fmt); if (!(fmt.dwMask & PFM_BORDER)) { @@ -678,6 +684,7 @@ static void ME_RTFParAttrHook(RTF_Info *info) fmt.dwMask = PFM_BORDER; break; case rtfBorderTop: + info->borderType = RTFBorderParaTop; ME_GetSelectionParaFormat(info->editor, &fmt); if (!(fmt.dwMask & PFM_BORDER)) { @@ -689,6 +696,7 @@ static void ME_RTFParAttrHook(RTF_Info *info) fmt.dwMask = PFM_BORDER; break; case rtfBorderBottom: + info->borderType = RTFBorderParaBottom; ME_GetSelectionParaFormat(info->editor, &fmt); if (!(fmt.dwMask & PFM_BORDER)) { @@ -735,11 +743,24 @@ static void ME_RTFParAttrHook(RTF_Info *info) fmt.dwMask = PFM_BORDER; break; case rtfBorderWidth: + { + int borderSide = info->borderType & RTFBorderSideMask; + RTFTable *tableDef = info->tableDef; ME_GetSelectionParaFormat(info->editor, &fmt); /* we assume that borders have been created before (RTF spec) */ fmt.wBorderWidth |= ((info->rtfParam / 15) & 7) << 8; + if ((info->borderType & RTFBorderTypeMask) == RTFBorderTypeCell) + { + RTFBorder *border; + if (!tableDef || tableDef->numCellsDefined >= MAX_TABLE_CELLS) + break; + border = &tableDef->cells[tableDef->numCellsDefined].border[borderSide]; + border->width = info->rtfParam; + break; + } fmt.dwMask = PFM_BORDER; break; + } case rtfBorderSpace: ME_GetSelectionParaFormat(info->editor, &fmt); /* we assume that borders have been created before (RTF spec) */ @@ -760,6 +781,10 @@ static void ME_RTFTblAttrHook(RTF_Info *info) { case rtfRowDef: { + if (!info->editor->bEmulateVersion10) /* v4.1 */ + info->borderType = 0; /* Not sure */ + else /* v1.0 - 3.0 */ + info->borderType = RTFBorderRowTop; if (!info->tableDef) { info->tableDef = ME_MakeTableDef(info->editor); } else { @@ -786,6 +811,30 @@ static void ME_RTFTblAttrHook(RTF_Info *info) } info->tableDef->numCellsDefined++; break; + case rtfRowBordTop: + info->borderType = RTFBorderRowTop; + break; + case rtfRowBordLeft: + info->borderType = RTFBorderRowLeft; + break; + case rtfRowBordBottom: + info->borderType = RTFBorderRowBottom; + break; + case rtfRowBordRight: + info->borderType = RTFBorderRowRight; + break; + case rtfCellBordTop: + info->borderType = RTFBorderCellTop; + break; + case rtfCellBordLeft: + info->borderType = RTFBorderCellLeft; + break; + case rtfCellBordBottom: + info->borderType = RTFBorderCellBottom; + break; + case rtfCellBordRight: + info->borderType = RTFBorderCellRight; + break; case rtfRowGapH: if (info->tableDef) info->tableDef->gapH = info->rtfParam; @@ -882,6 +931,10 @@ static void ME_RTFSpecialCharHook(RTF_Info *info) for (i = 0; i < tableDef->numCellsDefined; i++) { cell->member.cell.nRightBoundary = tableDef->cells[i].rightBoundary; + cell->member.cell.border.top.width = tableDef->cells[i].border[0].width; + cell->member.cell.border.left.width = tableDef->cells[i].border[1].width; + cell->member.cell.border.bottom.width = tableDef->cells[i].border[2].width; + cell->member.cell.border.right.width = tableDef->cells[i].border[3].width; cell = cell->member.cell.next_cell; if (!cell) { diff --git a/dlls/riched20/editstr.h b/dlls/riched20/editstr.h index 105ce05..3c4a083 100644 --- a/dlls/riched20/editstr.h +++ b/dlls/riched20/editstr.h @@ -165,6 +165,19 @@ typedef struct tagME_Document { int last_wrapped_line; } ME_Document; +typedef struct tagME_Border +{ + int width; +} ME_Border; + +typedef struct tagME_BorderRect +{ + ME_Border top; + ME_Border left; + ME_Border bottom; + ME_Border right; +} ME_BorderRect; + typedef struct tagME_Paragraph { PARAFORMAT2 *pFmt; @@ -184,8 +197,10 @@ typedef struct tagME_Cell /* v4.1 */ { int nNestingLevel; /* 0 for normal cells, and greater for nested cells */ int nRightBoundary; + ME_BorderRect border; POINT pt; int nHeight, nWidth; + int yTextOffset; /* The text offset is caused by the largest top border. */ struct tagME_DisplayItem *prev_cell, *next_cell, *parent_cell; } ME_Cell; diff --git a/dlls/riched20/paint.c b/dlls/riched20/paint.c index b2a8aed..a7636d9 100644 --- a/dlls/riched20/paint.c +++ b/dlls/riched20/paint.c @@ -36,6 +36,7 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, const RECT * item = editor->pBuffer->pFirst->next; c.pt.y -= yoffset; while(item != editor->pBuffer->pLast) { + int yTextOffset = 0; int ye; assert(item->type == diParagraph); if (item->member.para.pCell @@ -47,6 +48,19 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, const RECT * } else { ye = c.pt.y + item->member.para.nHeight; } + if (!(item->member.para.nFlags & MEPF_ROWEND) && + item->member.para.pCell != item->member.para.prev_para->member.para.pCell) + { + ME_DisplayItem *cell; + if (item->member.para.prev_para->member.para.nFlags & MEPF_ROWSTART) + cell = item->member.para.pCell; + else + cell = item->member.para.prev_para->member.para.pCell; + assert(cell); + /* the border shifts the text down */ + yTextOffset = cell->member.cell.yTextOffset; + ye += yTextOffset; + } if (!bOnlyNew || (item->member.para.nFlags & MEPF_REPAINT)) { BOOL bPaint = (rcUpdate == NULL); @@ -54,30 +68,33 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, const RECT * bPaint = c.pt.ybottom && ye>rcUpdate->top; if (bPaint) { + c.pt.y += yTextOffset; ME_DrawParagraph(&c, item); - if (!rcUpdate || (rcUpdate->top<=c.pt.y && rcUpdate->bottom>=ye)) + if (!rcUpdate || (rcUpdate->top<=c.pt.y-yTextOffset && rcUpdate->bottom>=ye)) item->member.para.nFlags &= ~MEPF_REPAINT; } } if (item->member.para.pCell) { ME_Cell *cell = &item->member.para.pCell->member.cell; + ME_DisplayItem *next_para = item->member.para.next_para; c.pt.x = cell->pt.x + cell->nWidth; - if (item->member.para.pCell == item->member.para.next_para->member.para.pCell) + if (item->member.para.pCell == next_para->member.para.pCell && + !(next_para->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND))) { c.pt.y = ye; } else { - if (item->member.para.next_para->member.para.nFlags & MEPF_ROWSTART) + if (next_para->member.para.nFlags & MEPF_ROWSTART) { - cell = &ME_FindItemFwd(item->member.para.next_para, diCell)->member.cell; + cell = &ME_FindItemFwd(next_para, diCell)->member.cell; } - else if (item->member.para.next_para->member.para.nFlags & MEPF_ROWEND) + else if (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; + cell = &next_para->member.para.pCell->member.cell; } c.pt.y = cell->pt.y - yoffset; } @@ -548,14 +565,45 @@ static void ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y, RECT { int idx, border_width, top_border, bottom_border; RECT rc; + BOOL hasParaBorder; SetRectEmpty(bounds); if (!(para->pFmt->dwMask & (PFM_BORDER | PFM_SPACEBEFORE | PFM_SPACEAFTER))) return; border_width = top_border = bottom_border = 0; idx = (para->pFmt->wBorders >> 8) & 0xF; - if ((para->pFmt->dwMask & PFM_BORDER) && idx != 0 && (para->pFmt->wBorders & 0xF)) + hasParaBorder = (!(c->editor->bEmulateVersion10 && + para->pFmt->dwMask & PFM_TABLE && + para->pFmt->wEffects & PFE_TABLE) && + (para->pFmt->dwMask & PFM_BORDER) && + idx != 0 && + (para->pFmt->wBorders & 0xF)); + if (hasParaBorder) { + /* FIXME: wBorders is not stored as MSDN says in v1.0 - 4.1 of richedit + * controls. It actually stores the paragraph or row border style. Although + * the value isn't used for drawing, it is used for streaming out rich text. + * + * wBorders stores the border style for each side (top, left, bottom, right) + * using nibble (4 bits) to store each border style. The rich text format + * control words, and their associated value are the following: + * \brdrdash 0 + * \brdrdashsm 1 + * \brdrdb 2 + * \brdrdot 3 + * \brdrhair 4 + * \brdrs 5 + * \brdrth 6 + * \brdrtriple 7 + * + * The order of the sides stored actually differs from v1.0 to 3.0 and v4.1. + * The mask corresponding to each side for the version are the following: + * mask v1.0-3.0 v4.1 + * 0x000F top left + * 0x00F0 left top + * 0x0F00 bottom right + * 0xF000 right bottom + */ if (para->pFmt->wBorders & 0x00B0) FIXME("Unsupported border flags %x\n", para->pFmt->wBorders); border_width = ME_GetParaBorderWidth(c->editor, para->pFmt->wBorders); @@ -583,7 +631,9 @@ static void ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y, RECT FillRect(c->hDC, &rc, c->editor->hbrBackground); } - if ((para->pFmt->dwMask & PFM_BORDER) && idx != 0 && (para->pFmt->wBorders & 0xF)) { + /* Native richedit doesn't support paragraph borders in v1.0 - 4.1, + * but might support it in later versions. */ + if (hasParaBorder) { int pen_width; COLORREF pencr; HPEN pen = NULL, oldpen = NULL; @@ -665,8 +715,140 @@ static void ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y, RECT static void ME_DrawTableBorders(ME_Context *c, ME_DisplayItem *paragraph) { ME_Paragraph *para = ¶graph->member.para; - if (c->editor->bEmulateVersion10) /* v1.0 - 3.0 */ + if (!c->editor->bEmulateVersion10) /* v4.1 */ { + if (para->pCell) + { + RECT rc; + ME_Cell *cell = ¶->pCell->member.cell; + ME_DisplayItem *paraAfterRow; + HPEN pen, oldPen; + LOGBRUSH logBrush; + HBRUSH brush; + COLORREF color; + POINT oldPt; + int width; + BOOL atTop = (para->pCell != para->prev_para->member.para.pCell); + BOOL atBottom = (para->pCell != para->next_para->member.para.pCell); + int top = (atTop ? cell->pt.y : para->pt.y) - ME_GetYScrollPos(c->editor); + int bottom = (atBottom ? + cell->pt.y + cell->nHeight - ME_GetYScrollPos(c->editor): + top + para->nHeight + (atTop ? cell->yTextOffset : 0)); + rc.left = cell->pt.x; + rc.right = rc.left + cell->nWidth; + if (atTop) { + /* Erase gap before text if not all borders are the same height. */ + width = max(ME_twips2pointsY(c, cell->border.top.width), 1); + rc.top = top + width; + width = cell->yTextOffset - width; + rc.bottom = rc.top + width; + if (width) { + FillRect(c->hDC, &rc, c->editor->hbrBackground); + DeleteObject(brush); + } + } + /* Draw cell borders. + * The borders borders are draw in is left, top, bottom, right in order + * to be consistent with native richedit. This is noticeable from the + * overlap of borders of different colours. */ + if (!(para->nFlags & MEPF_ROWEND)) { + rc.top = top; + rc.bottom = bottom; + if (cell->border.left.width > 0) + { + color = RGB(0,0,0); + width = max(ME_twips2pointsX(c, cell->border.left.width), 1); + } else { + color = RGB(192,192,192); + width = 1; + } + logBrush.lbStyle = BS_SOLID; + logBrush.lbColor = color; + logBrush.lbHatch = 0; + pen = ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER, + width, &logBrush, 0, NULL); + oldPen = SelectObject(c->hDC, pen); + MoveToEx(c->hDC, rc.left, rc.top, &oldPt); + LineTo(c->hDC, rc.left, rc.bottom); + SelectObject(c->hDC, oldPen); + DeleteObject(pen); + MoveToEx(c->hDC, oldPt.x, oldPt.y, NULL); + } + + if (atTop) { + if (cell->border.top.width > 0) + { + brush = GetStockObject(BLACK_BRUSH); + width = max(ME_twips2pointsY(c, cell->border.top.width), 1); + } else { + brush = GetStockObject(LTGRAY_BRUSH); + width = 1; + } + rc.top = top; + rc.bottom = rc.top + width; + FillRect(c->hDC, &rc, brush); + } + + /* Draw the bottom border if at the last paragraph in the cell, and when + * in the last row of the table. */ + if (atBottom) { + int oldLeft = rc.left; + width = max(ME_twips2pointsY(c, cell->border.bottom.width), 1); + paraAfterRow = ME_GetTableRowEnd(paragraph)->member.para.next_para; + if (paraAfterRow->member.para.nFlags & MEPF_ROWSTART) { + ME_DisplayItem *nextEndCell; + nextEndCell = ME_FindItemBack(ME_GetTableRowEnd(paraAfterRow), diCell); + assert(nextEndCell && !nextEndCell->member.cell.next_cell); + rc.left = nextEndCell->member.cell.pt.x; + /* FIXME: Native draws FROM the bottom of the table rather than + * TO the bottom of the table in this case, but just doing so here + * will case the next row to erase the border. */ + /* + rc.top = bottom; + rc.bottom = rc.top + width; + */ + } + if (rc.left < rc.right) { + if (cell->border.bottom.width > 0) { + brush = GetStockObject(BLACK_BRUSH); + } else { + brush = GetStockObject(LTGRAY_BRUSH); + } + rc.bottom = bottom; + rc.top = rc.bottom - width; + FillRect(c->hDC, &rc, brush); + } + rc.left = oldLeft; + } + + /* Right border only drawn if at the end of the table row. */ + if (!cell->next_cell->member.cell.next_cell && + !(para->nFlags & MEPF_ROWSTART)) + { + rc.top = top; + rc.bottom = bottom; + if (cell->border.right.width > 0) { + color = RGB(0,0,0); + width = max(ME_twips2pointsX(c, cell->border.right.width), 1); + } else { + color = RGB(192,192,192); + width = 1; + } + logBrush.lbStyle = BS_SOLID; + logBrush.lbColor = color; + logBrush.lbHatch = 0; + pen = ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER, + width, &logBrush, 0, NULL); + oldPen = SelectObject(c->hDC, pen); + MoveToEx(c->hDC, rc.right - 1, rc.top, &oldPt); + LineTo(c->hDC, rc.right - 1, rc.bottom); + SelectObject(c->hDC, oldPen); + DeleteObject(pen); + MoveToEx(c->hDC, oldPt.x, oldPt.y, NULL); + } + } + } else { /* v1.0 - 3.0 */ + /* Draw simple table border */ if (para->pFmt->dwMask & PFM_TABLE && para->pFmt->wEffects & PFE_TABLE) { HPEN pen = NULL, oldpen = NULL; int i, firstX, startX, endX, rowY, rowBottom, nHeight; @@ -785,7 +967,7 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) { pt.y = 12+y; ME_DebugWrite(c->hDC, &pt, buf); } - + height = p->member.row.nHeight; baseline = p->member.row.nBaseline; break; @@ -830,6 +1012,7 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) { { FillRect(c->hDC, &rc, c->editor->hbrBackground); } + break; default: break; } diff --git a/dlls/riched20/reader.c b/dlls/riched20/reader.c index 66b8ef7..8801137 100644 --- a/dlls/riched20/reader.c +++ b/dlls/riched20/reader.c @@ -247,6 +247,7 @@ void RTFInit(RTF_Info *info) info->tableDef = NULL; info->nestingLevel = 0; info->canInheritInTbl = FALSE; + info->borderType = 0; } /* diff --git a/dlls/riched20/rtf.h b/dlls/riched20/rtf.h index 84ddf5c..5cf699b 100644 --- a/dlls/riched20/rtf.h +++ b/dlls/riched20/rtf.h @@ -950,6 +950,7 @@ typedef struct RTFFont RTFFont; typedef struct RTFColor RTFColor; typedef struct RTFStyle RTFStyle; typedef struct RTFStyleElt RTFStyleElt; +typedef struct RTFBorder RTFBorder; typedef struct RTFCell RTFCell; typedef struct RTFTable RTFTable; @@ -1006,10 +1007,15 @@ struct RTFStyleElt RTFStyleElt *rtfNextSE; /* next element in style */ }; +struct RTFBorder +{ + int width; +}; struct RTFCell { int rightBoundary; + RTFBorder border[4]; }; @@ -1019,6 +1025,8 @@ struct RTFTable int numCellsDefined; int gapH, leftEdge; + /* borders for the table row */ + RTFBorder border[6]; /* Used in v1.0 - v3.0 */ int numCellsInserted; @@ -1033,6 +1041,40 @@ struct RTFTable RTFTable *parent; }; + +# define RTFBorderTypeNone 0x00 +# define RTFBorderTypePara 0x10 /* for \brdrX control words */ +# define RTFBorderTypeRow 0x20 /* for \trbrdrX control words */ +# define RTFBorderTypeCell 0x30 /* for \clbrdrX control words */ +# define RTFBorderTypeMask 0xf0 + +/* The X in the control words \brdrX \trbrdrX and \clbrdrX mentioned above + * should be one of t, l, b, r which stand for top, left, bottom, right + * respectively. */ +# define RTFBorderSideTop 0x00 +# define RTFBorderSideLeft 0x01 +# define RTFBorderSideBottom 0x02 +# define RTFBorderSideRight 0x03 +# define RTFBorderSideHorizontal 0x04 +# define RTFBorderSideVertical 0x05 +# define RTFBorderSideMask 0x0f + +/* Here are the values from the border types and sides put together. */ +# define RTFBorderParaTop 0x10 +# define RTFBorderParaLeft 0x11 +# define RTFBorderParaBottom 0x12 +# define RTFBorderParaRight 0x13 +# define RTFBorderRowTop 0x20 +# define RTFBorderRowLeft 0x21 +# define RTFBorderRowBottom 0x22 +# define RTFBorderRowRight 0x23 +# define RTFBorderRowHorizontal 0x24 +# define RTFBorderRowVertical 0x25 +# define RTFBorderCellTop 0x30 +# define RTFBorderCellLeft 0x31 +# define RTFBorderCellBottom 0x32 +# define RTFBorderCellRight 0x33 + /* * Return pointer to new element of type t, or NULL * if no memory available. @@ -1141,6 +1183,7 @@ struct _RTF_Info { RTFTable *tableDef; int nestingLevel; BOOL canInheritInTbl; + int borderType; /* value corresponds to the RTFBorder constants. */ }; diff --git a/dlls/riched20/table.c b/dlls/riched20/table.c index e71350a..248ea11 100644 --- a/dlls/riched20/table.c +++ b/dlls/riched20/table.c @@ -608,6 +608,7 @@ struct RTFTable *ME_MakeTableDef(ME_TextEditor *editor) void ME_InitTableDef(ME_TextEditor *editor, struct RTFTable *tableDef) { ZeroMemory(tableDef->cells, sizeof(tableDef->cells)); + ZeroMemory(tableDef->border, sizeof(tableDef->border)); tableDef->numCellsDefined = 0; tableDef->leftEdge = 0; if (!editor->bEmulateVersion10) /* v4.1 */ diff --git a/dlls/riched20/wrap.c b/dlls/riched20/wrap.c index 70a552d..a3c5d54 100644 --- a/dlls/riched20/wrap.c +++ b/dlls/riched20/wrap.c @@ -606,8 +606,24 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) { { ME_DisplayItem *cell = ME_FindItemFwd(item, diCell); ME_DisplayItem *endRowPara; + int borderWidth = 0; cell->member.cell.pt = c.pt; - endRowPara = ME_GetTableRowEnd(item); + /* Offset the text by the largest top border width. */ + while (cell->member.cell.next_cell) { + borderWidth = max(borderWidth, cell->member.cell.border.top.width); + cell = cell->member.cell.next_cell; + } + endRowPara = ME_FindItemFwd(cell, diParagraph); + assert(endRowPara->member.para.nFlags & MEPF_ROWEND); + if (borderWidth > 0) + { + borderWidth = max(ME_twips2pointsY(&c, borderWidth), 1); + while (cell) { + cell->member.cell.yTextOffset = borderWidth; + cell = cell->member.cell.prev_cell; + } + c.pt.y += borderWidth; + } if (endRowPara->member.para.pFmt->dxStartIndent > 0) { int dxStartIndent = endRowPara->member.para.pFmt->dxStartIndent; @@ -620,13 +636,26 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) { { /* Set all the cells to the height of the largest cell */ ME_DisplayItem *startRowPara; - int prevHeight, nHeight; + int prevHeight, nHeight, bottomBorder = 0; ME_DisplayItem *cell = ME_FindItemBack(item, diCell); + if (!(item->member.para.next_para->member.para.nFlags & MEPF_ROWSTART)) + { + /* Last row, the bottom border is added to the height. */ + cell = cell->member.cell.prev_cell; + while (cell) + { + bottomBorder = max(bottomBorder, cell->member.cell.border.bottom.width); + cell = cell->member.cell.prev_cell; + } + bottomBorder = ME_twips2pointsY(&c, bottomBorder); + cell = ME_FindItemBack(item, diCell); + } prevHeight = cell->member.cell.nHeight; - nHeight = cell->member.cell.prev_cell->member.cell.nHeight; + nHeight = cell->member.cell.prev_cell->member.cell.nHeight + bottomBorder; cell->member.cell.nHeight = nHeight; item->member.para.nHeight = nHeight; cell = cell->member.cell.prev_cell; + cell->member.cell.nHeight = nHeight; while (cell->member.cell.prev_cell) { cell = cell->member.cell.prev_cell; @@ -664,6 +693,7 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) { c.pt.x = cell->pt.x + cell->nWidth; c.pt.y = cell->pt.y; cell->next_cell->member.cell.pt = c.pt; + c.pt.y += cell->yTextOffset; } else {