Example #1
0
static void
ME_SelectByType(ME_TextEditor *editor, ME_SelectionType selectionType)
{
  /* pCursor[0] is the end of the selection
   * pCursor[1] is the start of the selection (or the position selection anchor)
   * pCursor[2] and [3] are the selection anchors that are backed up
   * so they are kept when the selection changes for drag selection.
   */

  editor->nSelectionType = selectionType;
  switch(selectionType)
  {
    case stPosition:
      break;
    case stWord:
      ME_MoveCursorWords(editor, &editor->pCursors[0], +1);
      editor->pCursors[1] = editor->pCursors[0];
      ME_MoveCursorWords(editor, &editor->pCursors[1], -1);
      break;
    case stLine:
    case stParagraph:
    {
      ME_DisplayItem *pItem;
      ME_DIType fwdSearchType, backSearchType;
      if (selectionType == stParagraph) {
          backSearchType = diParagraph;
          fwdSearchType = diParagraphOrEnd;
      } else {
          backSearchType = diStartRow;
          fwdSearchType = diStartRowOrParagraphOrEnd;
      }
      pItem = ME_FindItemFwd(editor->pCursors[0].pRun, fwdSearchType);
      assert(pItem);
      if (pItem->type == diTextEnd)
          editor->pCursors[0].pRun = ME_FindItemBack(pItem, diRun);
      else
          editor->pCursors[0].pRun = ME_FindItemFwd(pItem, diRun);
      editor->pCursors[0].pPara = ME_GetParagraph(editor->pCursors[0].pRun);
      editor->pCursors[0].nOffset = 0;

      pItem = ME_FindItemBack(pItem, backSearchType);
      editor->pCursors[1].pRun = ME_FindItemFwd(pItem, diRun);
      editor->pCursors[1].pPara = ME_GetParagraph(editor->pCursors[1].pRun);
      editor->pCursors[1].nOffset = 0;
      break;
    }
    case stDocument:
      /* Select everything with cursor anchored from the start of the text */
      editor->nSelectionType = stDocument;
      ME_SetCursorToStart(editor, &editor->pCursors[1]);
      ME_SetCursorToEnd(editor, &editor->pCursors[0]);
      break;
    default: assert(0);
  }
  /* Store the anchor positions for extending the selection. */
  editor->pCursors[2] = editor->pCursors[0];
  editor->pCursors[3] = editor->pCursors[1];
}
Example #2
0
/* Make sure the cursor is not in the hidden table row start paragraph
 * without a selection. */
void ME_MoveCursorFromTableRowStartParagraph(ME_TextEditor *editor)
{
    ME_DisplayItem *para = ME_GetParagraph(editor->pCursors[0].pRun);
    if (para == ME_GetParagraph(editor->pCursors[1].pRun) &&
            para->member.para.nFlags & MEPF_ROWSTART) {
        /* The cursors should not be at the hidden start row paragraph without
         * a selection, so the cursor is moved into the first cell. */
        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];
    }
}
Example #3
0
/* Extends the selection with a word, line, or paragraph selection type.
 *
 * The selection is anchored by editor->pCursors[2-3] such that the text
 * between the anchors will remain selected, and one end will be extended.
 *
 * editor->pCursors[0] should have the position to extend the selection to
 * before this function is called.
 *
 * Nothing will be done if editor->nSelectionType equals stPosition.
 */
static void ME_ExtendAnchorSelection(ME_TextEditor *editor)
{
  ME_Cursor tmp_cursor;
  int curOfs, anchorStartOfs, anchorEndOfs;
  if (editor->nSelectionType == stPosition || editor->nSelectionType == stDocument)
      return;
  curOfs = ME_GetCursorOfs(&editor->pCursors[0]);
  anchorStartOfs = ME_GetCursorOfs(&editor->pCursors[3]);
  anchorEndOfs = ME_GetCursorOfs(&editor->pCursors[2]);

  tmp_cursor = editor->pCursors[0];
  editor->pCursors[0] = editor->pCursors[2];
  editor->pCursors[1] = editor->pCursors[3];
  if (curOfs < anchorStartOfs)
  {
      /* Extend the left side of selection */
      editor->pCursors[1] = tmp_cursor;
      if (editor->nSelectionType == stWord)
          ME_MoveCursorWords(editor, &editor->pCursors[1], -1);
      else
      {
          ME_DisplayItem *pItem;
          ME_DIType searchType = ((editor->nSelectionType == stLine) ?
                                  diStartRowOrParagraph:diParagraph);
          pItem = ME_FindItemBack(editor->pCursors[1].pRun, searchType);
          editor->pCursors[1].pRun = ME_FindItemFwd(pItem, diRun);
          editor->pCursors[1].pPara = ME_GetParagraph(editor->pCursors[1].pRun);
          editor->pCursors[1].nOffset = 0;
      }
  }
  else if (curOfs >= anchorEndOfs)
  {
      /* Extend the right side of selection */
      editor->pCursors[0] = tmp_cursor;
      if (editor->nSelectionType == stWord)
          ME_MoveCursorWords(editor, &editor->pCursors[0], +1);
      else
      {
          ME_DisplayItem *pItem;
          ME_DIType searchType = ((editor->nSelectionType == stLine) ?
                                  diStartRowOrParagraphOrEnd:diParagraphOrEnd);
          pItem = ME_FindItemFwd(editor->pCursors[0].pRun, searchType);
          if (pItem->type == diTextEnd)
              editor->pCursors[0].pRun = ME_FindItemBack(pItem, diRun);
          else
              editor->pCursors[0].pRun = ME_FindItemFwd(pItem, diRun);
          editor->pCursors[0].pPara = ME_GetParagraph(editor->pCursors[0].pRun);
          editor->pCursors[0].nOffset = 0;
      }
  }
}
Example #4
0
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;
}
Example #5
0
/******************************************************************************
 * ME_JoinRuns
 * 
 * Merges two adjacent runs, the one given as a parameter and the next one.
 */    
void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p)
{
  ME_DisplayItem *pNext = p->next;
  int i;
  assert(p->type == diRun && pNext->type == diRun);
  assert(p->member.run.nCharOfs != -1);
  ME_GetParagraph(p)->member.para.nFlags |= MEPF_REWRAP;

  /* Update all cursors so that they don't contain the soon deleted run */
  for (i=0; i<editor->nCursors; i++) {
    if (editor->pCursors[i].pRun == pNext) {
      editor->pCursors[i].pRun = p;
      editor->pCursors[i].nOffset += p->member.run.len;
    }
  }

  p->member.run.len += pNext->member.run.len;
  ME_Remove(pNext);
  ME_DestroyDisplayItem(pNext);
  ME_UpdateRunFlags(editor, &p->member.run);
  if(TRACE_ON(richedit))
  {
    TRACE("Before check after join\n");
    ME_CheckCharOffsets(editor);
    TRACE("After check after join\n");
  }
}
Example #6
0
int ME_GetCursorOfs(ME_TextEditor *editor, int nCursor)
{
  ME_Cursor *pCursor = &editor->pCursors[nCursor];
  
  return ME_GetParagraph(pCursor->pRun)->member.para.nCharOfs
    + pCursor->pRun->member.run.nCharOfs + pCursor->nOffset;
}
Example #7
0
static void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
{
  ME_DisplayItem *pLast;
  int x, y;

  /* Find y position of the last row */
  pLast = editor->pBuffer->pLast;
  y = pLast->member.para.prev_para->member.para.pt.y
      + ME_FindItemBack(pLast, diStartRow)->member.row.pt.y;

  x = ME_GetXForArrow(editor, pCursor);

  if (editor->vert_si.nPos >= y - editor->sizeWindow.cy)
  {
    ME_SetCursorToEnd(editor, pCursor);
    editor->bCaretAtEnd = FALSE;
  } else {
    ME_DisplayItem *pRun = pCursor->pRun;
    ME_DisplayItem *p;
    int yd, yp;
    int yOldScrollPos = editor->vert_si.nPos;

    if (!pCursor->nOffset && editor->bCaretAtEnd)
      pRun = ME_FindItemBack(pRun, diRun);

    p = ME_FindItemBack(pRun, diStartRowOrParagraph);
    assert(p->type == diStartRow);
    yp = ME_FindItemBack(p, diParagraph)->member.para.pt.y;
    y = yp + p->member.row.pt.y;

    /* For native richedit controls:
     * v1.0 - v3.1 can only scroll down as far as the scrollbar lets us
     * v4.1 can scroll past this position here. */
    ME_ScrollDown(editor, editor->sizeWindow.cy);
    /* Only move the cursor by the amount scrolled. */
    yd = y + editor->vert_si.nPos - yOldScrollPos;
    pLast = p;

    do {
      p = ME_FindItemFwd(p, diStartRowOrParagraph);
      if (!p)
        break;
      if (p->type == diParagraph) {
        yp = p->member.para.pt.y;
        continue;
      }
      y = yp + p->member.row.pt.y;
      if (y >= yd)
        break;
      pLast = p;
    } while(1);

    pCursor->pRun = ME_FindRunInRow(editor, pLast, x, &pCursor->nOffset,
                                    &editor->bCaretAtEnd);
    pCursor->pPara = ME_GetParagraph(pCursor->pRun);
  }
  assert(pCursor->pRun);
  assert(pCursor->pRun->type == diRun);
}
Example #8
0
/* Finds the run and offset from the pixel position.
 *
 * x & y are pixel positions in virtual coordinates into the rich edit control,
 * so client coordinates must first be adjusted by the scroll position.
 *
 * returns TRUE if the result was exactly under the cursor, otherwise returns
 * FALSE, and result is set to the closest position to the coordinates.
 */
static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y,
                            ME_Cursor *result, BOOL *is_eol)
{
  ME_DisplayItem *p = editor->pBuffer->pFirst->member.para.next_para;
  BOOL isExact = TRUE;

  x -= editor->rcFormat.left;
  y -= editor->rcFormat.top;

  if (is_eol)
    *is_eol = FALSE;

  /* find paragraph */
  for (; p != editor->pBuffer->pLast; p = p->member.para.next_para)
  {
    assert(p->type == diParagraph);
    if (y < p->member.para.pt.y + p->member.para.nHeight)
    {
      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 */
  for (; p != editor->pBuffer->pLast; )
  {
    ME_DisplayItem *pp;
    assert(p->type == diStartRow);
    if (y < p->member.row.pt.y + p->member.row.nHeight) break;
    pp = ME_FindItemFwd(p, diStartRow);
    if (!pp) break;
    p = pp;
  }
  if (p == editor->pBuffer->pLast)
  {
    /* The position is below the last paragraph, so the last row will be used
     * rather than the end of the text, so the x position will be used to
     * determine the offset closest to the pixel position. */
    isExact = FALSE;
    p = ME_FindItemBack(p, diStartRow);
    if (!p) p = editor->pBuffer->pLast;
  }

  assert( p->type == diStartRow || p == editor->pBuffer->pLast );

  if( p->type == diStartRow )
      return ME_FindRunInRow( editor, p, x, result, is_eol ) && isExact;

  result->pRun = ME_FindItemBack(p, diRun);
  result->pPara = ME_GetParagraph(result->pRun);
  result->nOffset = 0;
  assert(result->pRun->member.run.nFlags & MERF_ENDPARA);
  return FALSE;
}
Example #9
0
static void ME_WrapSizeRun(ME_WrapContext *wc, ME_DisplayItem *p)
{
  /* FIXME compose style (out of character and paragraph styles) here */

  ME_UpdateRunFlags(wc->context->editor, &p->member.run);

  ME_CalcRunExtent(wc->context, &ME_GetParagraph(p)->member.para,
                   wc->nRow ? wc->nLeftMargin : wc->nFirstMargin, &p->member.run);
}
Example #10
0
static void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
{
  ME_DisplayItem *p = ME_FindItemFwd(editor->pBuffer->pFirst, diStartRow);

  if (editor->vert_si.nPos < p->member.row.nHeight)
  {
    ME_SetCursorToStart(editor, pCursor);
    editor->bCaretAtEnd = FALSE;
    /* Native clears seems to clear this x value on page up at the top
     * of the text, but not on page down at the end of the text.
     * Doesn't make sense, but we try to be bug for bug compatible. */
    editor->nUDArrowX = -1;
  } else {
    ME_DisplayItem *pRun = pCursor->pRun;
    ME_DisplayItem *pLast;
    int x, y, yd, yp;
    int yOldScrollPos = editor->vert_si.nPos;

    x = ME_GetXForArrow(editor, pCursor);
    if (!pCursor->nOffset && editor->bCaretAtEnd)
      pRun = ME_FindItemBack(pRun, diRun);

    p = ME_FindItemBack(pRun, diStartRowOrParagraph);
    assert(p->type == diStartRow);
    yp = ME_FindItemBack(p, diParagraph)->member.para.pt.y;
    y = yp + p->member.row.pt.y;

    ME_ScrollUp(editor, editor->sizeWindow.cy);
    /* Only move the cursor by the amount scrolled. */
    yd = y + editor->vert_si.nPos - yOldScrollPos;
    pLast = p;

    do {
      p = ME_FindItemBack(p, diStartRowOrParagraph);
      if (!p)
        break;
      if (p->type == diParagraph) { /* crossing paragraphs */
        if (p->member.para.prev_para == NULL)
          break;
        yp = p->member.para.prev_para->member.para.pt.y;
        continue;
      }
      y = yp + p->member.row.pt.y;
      if (y < yd)
        break;
      pLast = p;
    } while(1);

    pCursor->pRun = ME_FindRunInRow(editor, pLast, x, &pCursor->nOffset,
                                    &editor->bCaretAtEnd);
    pCursor->pPara = ME_GetParagraph(pCursor->pRun);
  }
  assert(pCursor->pRun);
  assert(pCursor->pRun->type == diRun);
}
Example #11
0
static BOOL ME_FindRunInRow(ME_TextEditor *editor, ME_DisplayItem *pRow,
                            int x, ME_Cursor *cursor, BOOL *pbCaretAtEnd)
{
  ME_DisplayItem *pNext, *pLastRun;
  ME_Row *row = &pRow->member.row;
  BOOL exact = TRUE;

  if (x < row->pt.x)
  {
      x = row->pt.x;
      exact = FALSE;
  }
  pNext = ME_FindItemFwd(pRow, diRunOrStartRow);
  assert(pNext->type == diRun);
  if (pbCaretAtEnd) *pbCaretAtEnd = FALSE;
  cursor->nOffset = 0;
  do {
    int run_x = pNext->member.run.pt.x;
    int width = pNext->member.run.nWidth;

    if (x >= run_x && x < run_x+width)
    {
      cursor->nOffset = ME_CharFromPoint(editor, x-run_x, &pNext->member.run, TRUE, TRUE);
      cursor->pRun = pNext;
      cursor->pPara = ME_GetParagraph( cursor->pRun );
      return exact;
    }
    pLastRun = pNext;
    pNext = ME_FindItemFwd(pNext, diRunOrStartRow);
  } while(pNext && pNext->type == diRun);

  if ((pLastRun->member.run.nFlags & MERF_ENDPARA) == 0)
  {
    cursor->pRun = ME_FindItemFwd(pNext, diRun);
    if (pbCaretAtEnd) *pbCaretAtEnd = TRUE;
  }
  else
    cursor->pRun = pLastRun;

  cursor->pPara = ME_GetParagraph( cursor->pRun );
  return FALSE;
}
Example #12
0
BOOL ME_IsInTable(ME_DisplayItem *pItem)
{
    PARAFORMAT2 *pFmt;
    if (!pItem)
        return FALSE;
    if (pItem->type == diRun)
        pItem = ME_GetParagraph(pItem);
    if (pItem->type != diParagraph)
        return FALSE;
    pFmt = pItem->member.para.pFmt;
    return pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE;
}
Example #13
0
void
ME_GetSelectionParas(ME_TextEditor *editor, ME_DisplayItem **para, ME_DisplayItem **para_end)
{
  ME_Cursor *pEndCursor = &editor->pCursors[1];
  
  *para = ME_GetParagraph(editor->pCursors[0].pRun);
  *para_end = ME_GetParagraph(editor->pCursors[1].pRun);
  if ((*para_end)->member.para.nCharOfs < (*para)->member.para.nCharOfs) {
    ME_DisplayItem *tmp = *para;

    *para = *para_end;
    *para_end = tmp;
    pEndCursor = &editor->pCursors[0];
  }
  
  /* selection consists of chars from nFrom up to nTo-1 */
  if ((*para_end)->member.para.nCharOfs > (*para)->member.para.nCharOfs) {
    if (!pEndCursor->nOffset) {
      *para_end = ME_GetParagraph(ME_FindItemBack(pEndCursor->pRun, diRun));
    }
  }
}
Example #14
0
int
ME_CharFromPos(ME_TextEditor *editor, int x, int y)
{
  ME_Cursor cursor;
  RECT rc;

  GetClientRect(editor->hWnd, &rc);
  if (x < 0 || y < 0 || x >= rc.right || y >= rc.bottom)
    return -1;
  y += ME_GetYScrollPos(editor);
  ME_FindPixelPos(editor, x, y, &cursor, NULL);
  return (ME_GetParagraph(cursor.pRun)->member.para.nCharOfs
          + cursor.pRun->member.run.nCharOfs + cursor.nOffset);
}
Example #15
0
static void ME_ArrowEnd(ME_TextEditor *editor, ME_Cursor *pCursor)
{
  ME_DisplayItem *pRow;

  if (editor->bCaretAtEnd && !pCursor->nOffset)
    return;

  pRow = ME_FindItemFwd(pCursor->pRun, diStartRowOrParagraphOrEnd);
  assert(pRow);
  if (pRow->type == diStartRow) {
    ME_DisplayItem *pRun = ME_FindItemFwd(pRow, diRun);
    assert(pRun);
    pCursor->pRun = pRun;
    assert(pCursor->pPara == ME_GetParagraph(pCursor->pRun));
    pCursor->nOffset = 0;
    editor->bCaretAtEnd = TRUE;
    return;
  }
  pCursor->pRun = ME_FindItemBack(pRow, diRun);
  assert(pCursor->pRun && pCursor->pRun->member.run.nFlags & MERF_ENDPARA);
  assert(pCursor->pPara == ME_GetParagraph(pCursor->pRun));
  pCursor->nOffset = 0;
  editor->bCaretAtEnd = FALSE;
}
Example #16
0
static BOOL ME_ReturnFoundPos(ME_TextEditor *editor, ME_DisplayItem *found,
                               ME_Cursor *result, int rx, BOOL isExact)
{
  assert(found);
  assert(found->type == diRun);
  if ((found->member.run.nFlags & MERF_ENDPARA) || rx < 0)
    rx = 0;
  result->pRun = found;
  result->nOffset = ME_CharFromPointCursor(editor, rx, &found->member.run);
  if (result->nOffset == found->member.run.len && rx)
  {
    result->pRun = ME_FindItemFwd(result->pRun, diRun);
    result->nOffset = 0;
  }
  result->pPara = ME_GetParagraph(result->pRun);
  return isExact;
}
Example #17
0
/* Returns the character offset closest to the pixel position
 *
 * x & y are pixel positions in client coordinates.
 *
 * isExact will be set to TRUE if the run is directly under the pixel
 * position, FALSE if it not, unless isExact is set to NULL.
 */
int ME_CharFromPos(ME_TextEditor *editor, int x, int y, BOOL *isExact)
{
  ME_Cursor cursor;
  RECT rc;
  BOOL bResult;

  GetClientRect(editor->hWnd, &rc);
  if (x < 0 || y < 0 || x >= rc.right || y >= rc.bottom) {
    if (isExact) *isExact = FALSE;
    return -1;
  }
  x += editor->horz_si.nPos;
  y += editor->vert_si.nPos;
  bResult = ME_FindPixelPos(editor, x, y, &cursor, NULL);
  if (isExact) *isExact = bResult;
  return (ME_GetParagraph(cursor.pRun)->member.para.nCharOfs
          + cursor.pRun->member.run.nCharOfs + cursor.nOffset);
}
Example #18
0
static void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
{
  ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diStartRow);
  if (pRow) {
    ME_DisplayItem *pRun;
    if (editor->bCaretAtEnd && !pCursor->nOffset) {
      pRow = ME_FindItemBack(pRow, diStartRow);
      if (!pRow)
        return;
    }
    pRun = ME_FindItemFwd(pRow, diRun);
    if (pRun) {
      pCursor->pRun = pRun;
      assert(pCursor->pPara == ME_GetParagraph(pRun));
      pCursor->nOffset = 0;
    }
  }
  editor->bCaretAtEnd = FALSE;
}
Example #19
0
static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd)
{
  ME_DisplayItem *p, *row, *para;
  int ascent = 0, descent = 0, width=0, shift = 0, align = 0;
  /* wrap text */
  para = ME_GetParagraph(wc->pRowStart);
  for (p = wc->pRowStart; p!=pEnd; p = p->next)
  {
    /* ENDPARA run shouldn't affect row height, except if it's the only run in the paragraph */
    if (p->type==diRun && ((p==wc->pRowStart) || !(p->member.run.nFlags & MERF_ENDPARA))) { /* FIXME add more run types */
      if (p->member.run.nAscent>ascent)
        ascent = p->member.run.nAscent;
      if (p->member.run.nDescent>descent)
        descent = p->member.run.nDescent;
      if (!(p->member.run.nFlags & (MERF_ENDPARA|MERF_SKIPPED)))
        width += p->member.run.nWidth;
    }
  }
  row = ME_MakeRow(ascent+descent, ascent, width);
  row->member.row.nYPos = wc->pt.y;
  row->member.row.nLMargin = (!wc->nRow ? wc->nFirstMargin : wc->nLeftMargin);
  row->member.row.nRMargin = wc->nRightMargin;
  assert(para->member.para.pFmt->dwMask & PFM_ALIGNMENT);
  align = para->member.para.pFmt->wAlignment;
  if (align == PFA_CENTER)
    shift = (wc->nAvailWidth-width)/2;
  if (align == PFA_RIGHT)
    shift = wc->nAvailWidth-width;
  for (p = wc->pRowStart; p!=pEnd; p = p->next)
  {
    if (p->type==diRun) { /* FIXME add more run types */
      p->member.run.pt.x += row->member.row.nLMargin+shift;
    }
  }
  ME_InsertBefore(wc->pRowStart, row);
  wc->nRow++;
  wc->pt.y += ascent+descent;
  ME_BeginRow(wc);
}
Example #20
0
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;
}
Example #21
0
static void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem)
{
  ME_UndoItem *pUItem = (ME_UndoItem *)pItem;

  if (editor->nUndoMode == umIgnore)
    return;
  TRACE("Playing undo/redo item, id=%s\n", ME_GetDITypeName(pItem->type));

  switch(pItem->type)
  {
  case diUndoPotentialEndTransaction:
  case diUndoEndTransaction:
    assert(0);
  case diUndoSetParagraphFormat:
  {
    ME_Cursor tmp;
    ME_DisplayItem *para;
    ME_CursorFromCharOfs(editor, pItem->member.para.nCharOfs, &tmp);
    para = ME_FindItemBack(tmp.pRun, diParagraph);
    ME_AddUndoItem(editor, diUndoSetParagraphFormat, para);
    *para->member.para.pFmt = *pItem->member.para.pFmt;
    para->member.para.border = pItem->member.para.border;
    break;
  }
  case diUndoSetCharFormat:
  {
    ME_SetCharFormat(editor, pUItem->nStart, pUItem->nLen, &pItem->member.ustyle->fmt);
    break;
  }
  case diUndoInsertRun:
  {
    ME_InsertRun(editor, pItem->member.run.nCharOfs, pItem);
    break;
  }
  case diUndoDeleteRun:
  {
    ME_InternalDeleteText(editor, pUItem->nStart, pUItem->nLen, TRUE);
    break;
  }
  case diUndoJoinParagraphs:
  {
    ME_Cursor tmp;
    ME_CursorFromCharOfs(editor, pUItem->nStart, &tmp);
    /* the only thing that's needed is paragraph offset, so no need to split runs */
    ME_JoinParagraphs(editor, ME_GetParagraph(tmp.pRun), TRUE);
    break;
  }
  case diUndoSplitParagraph:
  {
    ME_Cursor tmp;
    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, 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;
    new_para->member.para.border = pItem->member.para.border;
    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;
      pCell->member.cell.border = pItemCell->member.cell.border;
    }
    break;
  }
  default:
    assert(0 == "PlayUndoItem, unexpected type");
  }
}
Example #22
0
static void
ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs)
{
  ME_DisplayItem *pRun = pCursor->pRun;
  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 */
    pItem = ME_FindItemBack(pRun, diStartRow);
    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)
  {
    /* row not found - ignore */
    return;
  }
  pCursor->pRun = ME_FindRunInRow(editor, pItem, x, &pCursor->nOffset, &editor->bCaretAtEnd);
  assert(pCursor->pRun);
  assert(pCursor->pRun->type == diRun);
}
Example #23
0
void
ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
                        int *x, int *y, int *height)
{
  ME_DisplayItem *pCursorRun = pCursor->pRun;
  ME_DisplayItem *pSizeRun = pCursor->pRun;

  assert(height && x && y);
  assert(!(ME_GetParagraph(pCursorRun)->member.para.nFlags & MEPF_REWRAP));
  assert(pCursor->pRun);
  assert(pCursor->pRun->type == diRun);

  if (pCursorRun->type == diRun) {
    ME_DisplayItem *row = ME_FindItemBack(pCursorRun, diStartRowOrParagraph);

    if (row) {
      HDC hDC = GetDC(editor->hWnd);
      ME_Context c;
      ME_DisplayItem *run = pCursorRun;
      ME_DisplayItem *para = NULL;
      SIZE sz = {0, 0};

      ME_InitContext(&c, editor, hDC);

      if (!pCursor->nOffset)
      {
        ME_DisplayItem *prev = ME_FindItemBack(pCursorRun, diRunOrParagraph);
        assert(prev);
        if (prev->type == diRun)
          pSizeRun = prev;
      }
      assert(row->type == diStartRow); /* paragraph -> run without start row ?*/
      para = ME_FindItemBack(row, diParagraph);
      assert(para);
      assert(para->type == diParagraph);
      if (editor->bCaretAtEnd && !pCursor->nOffset &&
          run == ME_FindItemFwd(row, diRun))
      {
        ME_DisplayItem *tmp = ME_FindItemBack(row, diRunOrParagraph);
        assert(tmp);
        if (tmp->type == diRun)
        {
          row = ME_FindItemBack(tmp, diStartRow);
          pSizeRun = run = tmp;
          assert(run);
          assert(run->type == diRun);
          sz = ME_GetRunSize(&c, &para->member.para,
                             &run->member.run, ME_StrLen(run->member.run.strText),
                             row->member.row.nLMargin);
        }
      }
      if (pCursor->nOffset) {
        sz = ME_GetRunSize(&c, &para->member.para, &run->member.run, pCursor->nOffset,
                           row->member.row.nLMargin);
      }

      *height = pSizeRun->member.run.nAscent + pSizeRun->member.run.nDescent;
      *x = c.rcView.left + run->member.run.pt.x + sz.cx - editor->horz_si.nPos;
      *y = c.rcView.top + para->member.para.pt.y + row->member.row.nBaseline
           + run->member.run.pt.y - pSizeRun->member.run.nAscent - editor->vert_si.nPos;
      ME_DestroyContext(&c, editor->hWnd);
      return;
    }
  }
  *height = 10; /* FIXME use global font */
  *x = 0;
  *y = 0;
}
Example #24
0
/* Table rows should either be deleted completely or not at all. */
void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, int nOfs,int *nChars)
{
    ME_Cursor c, c2;
    ME_DisplayItem *this_para, *end_para;
    ME_CursorFromCharOfs(editor, nOfs, &c);
    this_para = ME_GetParagraph(c.pRun);
    ME_CursorFromCharOfs(editor, nOfs + *nChars, &c2);
    end_para = ME_GetParagraph(c2.pRun);
    if (c2.pRun->member.run.nFlags & MERF_ENDPARA) {
        /* End offset might be in the middle of the end paragraph run.
         * If this is the case, then we need to use the next paragraph as the last
         * paragraphs.
         */
        int remaining = nOfs + *nChars - c2.pRun->member.run.nCharOfs
                        - end_para->member.para.nCharOfs;
        if (remaining)
        {
            assert(remaining < c2.pRun->member.run.nCR + c2.pRun->member.run.nLF);
            end_para = end_para->member.para.next_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)))
        {
            while (this_para != end_para)
            {
                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 { /* v1.0 - 3.0 */
        ME_DisplayItem *pRun;
        int nCharsToBoundary;

        if ((this_para->member.para.nCharOfs != nOfs || this_para == end_para) &&
                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)
        {
            /* 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;
    }
}
Example #25
0
File: para.c Project: AmesianX/wine
/* split paragraph at the beginning of the run */
ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run,
                                  ME_Style *style, const WCHAR *eol_str, int eol_len,
                                  int paraFlags)
{
  ME_DisplayItem *next_para = NULL;
  ME_DisplayItem *run_para = NULL;
  ME_DisplayItem *new_para = make_para(editor);
  ME_DisplayItem *end_run;
  int ofs, i;
  ME_DisplayItem *pp;
  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)));
  }
  assert(run->type == diRun);
  run_para = ME_GetParagraph(run);
  assert(run_para->member.para.pFmt->cbSize == sizeof(PARAFORMAT2));

  new_para->member.para.text = ME_VSplitString( run_para->member.para.text, run->member.run.nCharOfs );

  end_run = ME_MakeRun(style, run_flags);
  ofs = end_run->member.run.nCharOfs = run->member.run.nCharOfs;
  end_run->member.run.len = eol_len;
  end_run->member.run.para = run->member.run.para;
  ME_AppendString( run_para->member.para.text, eol_str, eol_len );
  next_para = run_para->member.para.next_para;
  assert(next_para == ME_FindItemFwd(run_para, diParagraphOrEnd));

  add_undo_join_paras( editor, run_para->member.para.nCharOfs + ofs );

  /* Update selection cursors to point to the correct paragraph. */
  for (i = 0; i < editor->nCursors; i++) {
    if (editor->pCursors[i].pPara == run_para &&
        run->member.run.nCharOfs <= editor->pCursors[i].pRun->member.run.nCharOfs)
    {
      editor->pCursors[i].pPara = new_para;
    }
  }

  /* the new paragraph will have a different starting offset, so let's update its runs */
  pp = run;
  while(pp->type == diRun) {
    pp->member.run.nCharOfs -= ofs;
    pp->member.run.para = &new_para->member.para;
    pp = ME_FindItemFwd(pp, diRunOrParagraphOrEnd);
  }
  new_para->member.para.nCharOfs = run_para->member.para.nCharOfs + ofs;
  new_para->member.para.nCharOfs += eol_len;
  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;
  new_para->member.para.border = run_para->member.para.border;

  /* insert paragraph into paragraph double linked list */
  new_para->member.para.prev_para = run_para;
  new_para->member.para.next_para = next_para;
  run_para->member.para.next_para = new_para;
  next_para->member.para.prev_para = new_para;

  /* insert end run of the old paragraph, and new paragraph, into DI double linked list */
  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));
      if (new_para->member.para.pCell != new_para->member.para.next_para->member.para.pCell
          && new_para->member.para.next_para->member.para.pCell
          && !new_para->member.para.next_para->member.para.pCell->member.cell.prev_cell)
      {
        /* Row starts just after the row that was ended. */
        new_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;

  /* we've added the end run, so we need to modify nCharOfs in the next paragraphs */
  ME_PropagateCharOffset(next_para, eol_len);
  editor->nParagraphs++;

  return new_para;
}
Example #26
0
/* Selects the next table cell or appends a new table row if at end of table */
static void ME_SelectOrInsertNextCell(ME_TextEditor *editor,
                                      ME_DisplayItem *run)
{
    ME_DisplayItem *para = ME_GetParagraph(run);
    int i;

    assert(run && run->type == diRun);
    assert(ME_IsInTable(run));
    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)
        {
            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;
            }
        }
        /* 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);
            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;
        }
    }
}
Example #27
0
/* Finds the run and offset from the pixel position.
 *
 * x & y are pixel positions in virtual coordinates into the rich edit control,
 * so client coordinates must first be adjusted by the scroll position.
 *
 * returns TRUE if the result was exactly under the cursor, otherwise returns
 * FALSE, and result is set to the closest position to the coordinates.
 */
static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y,
                            ME_Cursor *result, BOOL *is_eol)
{
  ME_DisplayItem *p = editor->pBuffer->pFirst->member.para.next_para;
  ME_DisplayItem *last = NULL;
  int rx = 0;
  BOOL isExact = TRUE;

  x -= editor->rcFormat.left;
  y -= editor->rcFormat.top;

  if (is_eol)
    *is_eol = 0;

  /* find paragraph */
  for (; p != editor->pBuffer->pLast; p = p->member.para.next_para)
  {
    assert(p->type == diParagraph);
    if (y < p->member.para.pt.y + p->member.para.nHeight)
    {
      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 */
  for (; p != editor->pBuffer->pLast; )
  {
    ME_DisplayItem *pp;
    assert(p->type == diStartRow);
    if (y < p->member.row.pt.y + p->member.row.nHeight)
    {
        p = ME_FindItemFwd(p, diRun);
        break;
    }
    pp = ME_FindItemFwd(p, diStartRowOrParagraphOrEnd);
    if (pp->type != diStartRow)
    {
        p = ME_FindItemFwd(p, diRun);
        break;
    }
    p = pp;
  }
  if (p == editor->pBuffer->pLast)
  {
    /* The position is below the last paragraph, so the last row will be used
     * rather than the end of the text, so the x position will be used to
     * determine the offset closest to the pixel position. */
    isExact = FALSE;
    p = ME_FindItemBack(p, diStartRow);
    if (p != NULL){
      p = ME_FindItemFwd(p, diRun);
    }
    else
    {
      p = editor->pBuffer->pLast;
    }
  }
  for (; p != editor->pBuffer->pLast; p = p->next)
  {
    switch (p->type)
    {
    case diRun:
      rx = x - p->member.run.pt.x;
      if (rx < p->member.run.nWidth)
        return ME_ReturnFoundPos(editor, p, result, rx, isExact);
      break;
    case diStartRow:
      isExact = FALSE;
      p = ME_FindItemFwd(p, diRun);
      if (is_eol) *is_eol = 1;
      rx = 0; /* FIXME not sure */
      return ME_ReturnFoundPos(editor, p, result, rx, isExact);
    case diCell:
    case diParagraph:
    case diTextEnd:
      isExact = FALSE;
      rx = 0; /* FIXME not sure */
      p = last;
      return ME_ReturnFoundPos(editor, p, result, rx, isExact);
    default: assert(0);
    }
    last = p;
  }
  result->pRun = ME_FindItemBack(p, diRun);
  result->pPara = ME_GetParagraph(result->pRun);
  result->nOffset = 0;
  assert(result->pRun->member.run.nFlags & MERF_ENDPARA);
  return FALSE;
}
Example #28
0
static ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
{
  ME_DisplayItem *pp;
  ME_Run *run;
  int len;

  assert(p->type == diRun);
  if (!wc->pRowStart)
    wc->pRowStart = p;
  run = &p->member.run;
  run->pt.x = wc->pt.x;
  run->pt.y = wc->pt.y;
  ME_WrapSizeRun(wc, p);
  len = ME_StrVLen(run->strText);

  if (wc->bOverflown) /* just skipping final whitespaces */
  {
    if (run->nFlags & (MERF_WHITESPACE|MERF_TAB)) {
      p->member.run.nFlags |= MERF_SKIPPED;
      /* wc->pt.x += run->nWidth; */
      /* skip runs consisting of only whitespaces */
      return p->next;
    }

    if (run->nFlags & MERF_STARTWHITE) {
      /* try to split the run at the first non-white char */
      int black;
      black = ME_FindNonWhitespaceV(run->strText, 0);
      if (black) {
        wc->bOverflown = FALSE;
        pp = ME_SplitRun(wc, p, black);
        p->member.run.nFlags |= MERF_SKIPPED;
        ME_InsertRowStart(wc, pp);
        return pp;
      }
    }
    /* black run: the row goes from pRowStart to the previous run */
    ME_InsertRowStart(wc, p);
    return p;
  }
  /* simply end the current row and move on to next one */
  if (run->nFlags & MERF_ENDROW)
  {
    p = p->next;
    ME_InsertRowStart(wc, p);
    return p;
  }
  /* we're not at the end of the row */
  if (run->nFlags & MERF_TAB) {
    /* force recomputation of tabs' size as it depends on position */
    ME_CalcRunExtent(wc->context, &ME_GetParagraph(p)->member.para,
                     wc->nRow ? wc->nLeftMargin : wc->nFirstMargin, run);
  }

  /* will current run fit? */
  if (wc->pt.x + run->nWidth > wc->nAvailWidth)
  {
    int loc = wc->nAvailWidth - wc->pt.x;
    /* total white run ? */
    if (run->nFlags & MERF_WHITESPACE) {
      /* let the overflow logic handle it */
      wc->bOverflown = TRUE;
      return p;
    }
    /* TAB: we can split before */
    if (run->nFlags & MERF_TAB) {
      wc->bOverflown = TRUE;
      return p;
    }
    /* graphics: we can split before, if run's width is smaller than row's width */
    if ((run->nFlags & MERF_GRAPHICS) && run->nWidth <= wc->nAvailWidth) {
      wc->bOverflown = TRUE;
      return p;
    }
    /* can we separate out the last spaces ? (to use overflow logic later) */
    if (run->nFlags & MERF_ENDWHITE)
    {
      /* we aren't sure if it's *really* necessary, it's a good start however */
      int black = ME_ReverseFindNonWhitespaceV(run->strText, len);
      ME_SplitRun(wc, p, black);
      /* handle both parts again */
      return p;
    }
    /* determine the split point by backtracking */
    pp = ME_SplitByBacktracking(wc, p, loc);
    if (pp == wc->pRowStart)
    {
      /* we had only spaces so far, entire content can be omitted */
      wc->pt.x = 0;
      return p->next;
    }
    if (p != pp) /* found a suitable split point */
    {
      wc->bOverflown = TRUE;
      return pp;
    }
    /* we detected that it's best to split on start of this run */
    if (wc->bOverflown)
      return pp;
    ERR("failure!\n");
    /* not found anything - writing over margins is the only option left */
  }
  if ((run->nFlags & (MERF_SPLITTABLE | MERF_STARTWHITE))
    || ((run->nFlags & (MERF_GRAPHICS|MERF_TAB)) && (p != wc->pRowStart)))
  {
    wc->pLastSplittableRun = p;
    wc->ptLastSplittableRun = wc->pt;
  }
  wc->pt.x += run->nWidth;
  return p->next;
}
Example #29
0
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;
    }
  }
}
Example #30
0
static void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem)
{
  ME_UndoItem *pUItem = (ME_UndoItem *)pItem;

  if (editor->nUndoMode == umIgnore)
    return;
  TRACE("Playing undo/redo item, id=%s\n", ME_GetDITypeName(pItem->type));

  switch(pItem->type)
  {
  case diUndoEndTransaction:
    assert(0);
  case diUndoSetParagraphFormat:
  {
    ME_Cursor tmp;
    ME_CursorFromCharOfs(editor, pItem->member.para.nCharOfs, &tmp);
    ME_SetParaFormat(editor, ME_FindItemBack(tmp.pRun, diParagraph), pItem->member.para.pFmt);
    break;
  }
  case diUndoSetCharFormat:
  {
    ME_SetCharFormat(editor, pUItem->nStart, pUItem->nLen, &pItem->member.ustyle->fmt);
    break;
  }
  case diUndoSetDefaultCharFormat:
  {
    ME_SetDefaultCharFormat(editor, &pItem->member.ustyle->fmt);
    break;
  }
  case diUndoInsertRun:
  {
    ME_InsertRun(editor, pItem->member.run.nCharOfs, pItem);
    break;
  }
  case diUndoDeleteRun:
  {
    ME_InternalDeleteText(editor, pUItem->nStart, pUItem->nLen);
    break;
  }
  case diUndoJoinParagraphs:
  {
    ME_Cursor tmp;
    ME_CursorFromCharOfs(editor, pUItem->nStart, &tmp);
    /* the only thing that's needed is paragraph offset, so no need to split runs */
    ME_JoinParagraphs(editor, ME_GetParagraph(tmp.pRun));
    break;
  }
  case diUndoSplitParagraph:
  {
    ME_Cursor tmp;
    ME_DisplayItem *new_para;
    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);
    new_para = ME_SplitParagraph(editor, tmp.pRun, tmp.pRun->member.run.style,
      pUItem->nCR, pUItem->nLF);
    assert(pItem->member.para.pFmt->cbSize == sizeof(PARAFORMAT2));
    *new_para->member.para.pFmt = *pItem->member.para.pFmt;
    break;
  }
  default:
    assert(0 == "PlayUndoItem, unexpected type");
  }
}