void ME_MakeFirstParagraph(ME_TextEditor *editor) { ME_Context c; CHARFORMAT2W cf; LOGFONTW lf; HFONT hf; ME_TextBuffer *text = editor->pBuffer; ME_DisplayItem *para = make_para(editor); ME_DisplayItem *run; ME_Style *style; int eol_len; WCHAR cr_lf[] = {'\r','\n',0}; ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost)); hf = GetStockObject(SYSTEM_FONT); assert(hf); GetObjectW(hf, sizeof(LOGFONTW), &lf); ZeroMemory(&cf, sizeof(cf)); cf.cbSize = sizeof(cf); cf.dwMask = CFM_BACKCOLOR|CFM_COLOR|CFM_FACE|CFM_SIZE|CFM_CHARSET; cf.dwMask |= CFM_ALLCAPS|CFM_BOLD|CFM_DISABLED|CFM_EMBOSS|CFM_HIDDEN; cf.dwMask |= CFM_IMPRINT|CFM_ITALIC|CFM_LINK|CFM_OUTLINE|CFM_PROTECTED; cf.dwMask |= CFM_REVISED|CFM_SHADOW|CFM_SMALLCAPS|CFM_STRIKEOUT; cf.dwMask |= CFM_SUBSCRIPT|CFM_UNDERLINETYPE|CFM_WEIGHT; cf.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR; lstrcpyW(cf.szFaceName, lf.lfFaceName); /* Convert system font height from logical units to twips for cf.yHeight */ cf.yHeight = (lf.lfHeight * 72 * 1440) / (c.dpi.cy * c.dpi.cy); if (lf.lfWeight > FW_NORMAL) cf.dwEffects |= CFE_BOLD; cf.wWeight = lf.lfWeight; if (lf.lfItalic) cf.dwEffects |= CFE_ITALIC; cf.bUnderlineType = (lf.lfUnderline) ? CFU_CF1UNDERLINE : CFU_UNDERLINENONE; if (lf.lfStrikeOut) cf.dwEffects |= CFE_STRIKEOUT; cf.bPitchAndFamily = lf.lfPitchAndFamily; cf.bCharSet = lf.lfCharSet; style = ME_MakeStyle(&cf); text->pDefaultStyle = style; eol_len = editor->bEmulateVersion10 ? 2 : 1; para->member.para.text = ME_MakeStringN( cr_lf, eol_len ); run = ME_MakeRun(style, MERF_ENDPARA); run->member.run.nCharOfs = 0; run->member.run.len = eol_len; run->member.run.para = ¶->member.para; ME_InsertBefore(text->pLast, para); ME_InsertBefore(text->pLast, run); para->member.para.prev_para = text->pFirst; para->member.para.next_para = text->pLast; text->pFirst->member.para.next_para = para; text->pLast->member.para.prev_para = para; text->pLast->member.para.nCharOfs = editor->bEmulateVersion10 ? 2 : 1; ME_DestroyContext(&c); }
BOOL ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars, BOOL bForce) { ME_Cursor c; int shift = 0; int totalChars = nChars; ME_DisplayItem *start_para; { /* Prevent deletion past last end of paragraph run. */ ME_DisplayItem *pTextEnd = editor->pBuffer->pLast; int nMaxChars = pTextEnd->member.para.prev_para->member.para.nCharOfs; nMaxChars += ME_FindItemBack(pTextEnd, diRun)->member.run.nCharOfs; nMaxChars -= nOfs; nChars = min(nChars, nMaxChars); } ME_CursorFromCharOfs(editor, nOfs, &c); start_para = ME_GetParagraph(c.pRun); if (!bForce) { ME_ProtectPartialTableDeletion(editor, nOfs, &nChars); if (nChars == 0) return FALSE; } while(nChars > 0) { ME_Run *run; ME_CursorFromCharOfs(editor, nOfs+nChars, &c); if (!c.nOffset && nOfs+nChars == (c.pRun->member.run.nCharOfs + ME_GetParagraph(c.pRun)->member.para.nCharOfs)) { /* We aren't deleting anything in this run, so we will go back to the * last run we are deleting text in. */ c.pRun = ME_FindItemBack(c.pRun, diRun); if (c.pRun->member.run.nFlags & MERF_ENDPARA) c.nOffset = c.pRun->member.run.nCR + c.pRun->member.run.nLF; else c.nOffset = c.pRun->member.run.strText->nLen; } run = &c.pRun->member.run; if (run->nFlags & MERF_ENDPARA) { int eollen = run->nCR + run->nLF; BOOL keepFirstParaFormat; if (!ME_FindItemFwd(c.pRun, diParagraph)) { return TRUE; } 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); nChars -= (eollen < nChars) ? eollen : nChars; continue; } else { ME_Cursor cursor; int nCharsToDelete = min(nChars, c.nOffset); int i; c.nOffset -= nCharsToDelete; ME_FindItemBack(c.pRun, diParagraph)->member.para.nFlags |= MEPF_REWRAP; cursor = c; /* nChars is the number of characters that should be deleted from the PRECEDING runs (these BEFORE cursor.pRun) nCharsToDelete is a number of chars to delete from THIS run */ nChars -= nCharsToDelete; shift -= nCharsToDelete; TRACE("Deleting %d (remaning %d) chars at %d in '%s' (%d)\n", nCharsToDelete, nChars, c.nOffset, debugstr_w(run->strText->szData), run->strText->nLen); if (!c.nOffset && ME_StrVLen(run->strText) == nCharsToDelete) { /* undo = reinsert whole run */ /* nOfs is a character offset (from the start of the document to the current (deleted) run */ ME_UndoItem *pUndo = ME_AddUndoItem(editor, diUndoInsertRun, c.pRun); if (pUndo) pUndo->di.member.run.nCharOfs = nOfs+nChars; } else { /* undo = reinsert partial run */ ME_UndoItem *pUndo = ME_AddUndoItem(editor, diUndoInsertRun, c.pRun); if (pUndo) { ME_DestroyString(pUndo->di.member.run.strText); pUndo->di.member.run.nCharOfs = nOfs+nChars; pUndo->di.member.run.strText = ME_MakeStringN(run->strText->szData+c.nOffset, nCharsToDelete); } } TRACE("Post deletion string: %s (%d)\n", debugstr_w(run->strText->szData), run->strText->nLen); TRACE("Shift value: %d\n", shift); ME_StrDeleteV(run->strText, c.nOffset, nCharsToDelete); /* update cursors (including c) */ for (i=-1; i<editor->nCursors; i++) { ME_Cursor *pThisCur = editor->pCursors + i; if (i == -1) pThisCur = &c; if (pThisCur->pRun == cursor.pRun) { if (pThisCur->nOffset > cursor.nOffset) { if (pThisCur->nOffset-cursor.nOffset < nCharsToDelete) pThisCur->nOffset = cursor.nOffset; else pThisCur->nOffset -= nCharsToDelete; assert(pThisCur->nOffset >= 0); assert(pThisCur->nOffset <= ME_StrVLen(run->strText)); } if (pThisCur->nOffset == ME_StrVLen(run->strText)) { pThisCur->pRun = ME_FindItemFwd(pThisCur->pRun, diRunOrParagraphOrEnd); assert(pThisCur->pRun->type == diRun); pThisCur->nOffset = 0; } } } /* c = updated data now */ if (c.pRun == cursor.pRun) ME_SkipAndPropagateCharOffset(c.pRun, shift); else ME_PropagateCharOffset(c.pRun, shift); if (!ME_StrVLen(cursor.pRun->member.run.strText)) { TRACE("Removing useless run\n"); ME_Remove(cursor.pRun); ME_DestroyDisplayItem(cursor.pRun); } shift = 0; /* ME_CheckCharOffsets(editor); */ continue; } } return TRUE; }
void ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars) { ME_Cursor c; int shift = 0; while(nChars > 0) { ME_Run *run; ME_CursorFromCharOfs(editor, nOfs, &c); run = &c.pRun->member.run; if (run->nFlags & MERF_ENDPARA) { int eollen = run->nCR + run->nLF; if (!ME_FindItemFwd(c.pRun, diParagraph)) { return; } ME_JoinParagraphs(editor, ME_GetParagraph(c.pRun)); /* ME_SkipAndPropagateCharOffset(p->pRun, shift); */ ME_CheckCharOffsets(editor); nChars -= (eollen < nChars) ? eollen : nChars; continue; } else { ME_Cursor cursor; int nIntendedChars = nChars; int nCharsToDelete = nChars; int i; int loc = c.nOffset; ME_FindItemBack(c.pRun, diParagraph)->member.para.nFlags |= MEPF_REWRAP; cursor = c; ME_StrRelPos(run->strText, loc, &nChars); /* nChars is the number of characters that should be deleted from the FOLLOWING runs (these AFTER cursor.pRun) nCharsToDelete is a number of chars to delete from THIS run */ nCharsToDelete -= nChars; shift -= nCharsToDelete; TRACE("Deleting %d (intended %d-remaning %d) chars at %d in '%s' (%d)\n", nCharsToDelete, nIntendedChars, nChars, c.nOffset, debugstr_w(run->strText->szData), run->strText->nLen); if (!c.nOffset && ME_StrVLen(run->strText) == nCharsToDelete) { /* undo = reinsert whole run */ /* nOfs is a character offset (from the start of the document to the current (deleted) run */ ME_UndoItem *pUndo = ME_AddUndoItem(editor, diUndoInsertRun, c.pRun); if (pUndo) pUndo->di.member.run.nCharOfs = nOfs; } else { /* undo = reinsert partial run */ ME_UndoItem *pUndo = ME_AddUndoItem(editor, diUndoInsertRun, c.pRun); if (pUndo) { ME_DestroyString(pUndo->di.member.run.strText); pUndo->di.member.run.nCharOfs = nOfs; pUndo->di.member.run.strText = ME_MakeStringN(run->strText->szData+c.nOffset, nCharsToDelete); } } TRACE("Post deletion string: %s (%d)\n", debugstr_w(run->strText->szData), run->strText->nLen); TRACE("Shift value: %d\n", shift); ME_StrDeleteV(run->strText, c.nOffset, nCharsToDelete); /* update cursors (including c) */ for (i=-1; i<editor->nCursors; i++) { ME_Cursor *pThisCur = editor->pCursors + i; if (i == -1) pThisCur = &c; if (pThisCur->pRun == cursor.pRun) { if (pThisCur->nOffset > cursor.nOffset) { if (pThisCur->nOffset-cursor.nOffset < nCharsToDelete) pThisCur->nOffset = cursor.nOffset; else pThisCur->nOffset -= nCharsToDelete; assert(pThisCur->nOffset >= 0); assert(pThisCur->nOffset <= ME_StrVLen(run->strText)); } if (pThisCur->nOffset == ME_StrVLen(run->strText)) { pThisCur->pRun = ME_FindItemFwd(pThisCur->pRun, diRunOrParagraphOrEnd); assert(pThisCur->pRun->type == diRun); pThisCur->nOffset = 0; } } } /* c = updated data now */ if (c.pRun == cursor.pRun) ME_SkipAndPropagateCharOffset(c.pRun, shift); else ME_PropagateCharOffset(c.pRun, shift); if (!ME_StrVLen(cursor.pRun->member.run.strText)) { TRACE("Removing useless run\n"); ME_Remove(cursor.pRun); ME_DestroyDisplayItem(cursor.pRun); } shift = 0; /* ME_CheckCharOffsets(editor); */ continue; } } }
ME_String *ME_StrDup(const ME_String *s) { return ME_MakeStringN(s->szData, s->nLen); }