Пример #1
0
int ME_GetSelection(ME_TextEditor *editor, ME_Cursor **from, ME_Cursor **to)
{
  int from_ofs = ME_GetCursorOfs( &editor->pCursors[0] );
  int to_ofs   = ME_GetCursorOfs( &editor->pCursors[1] );
  BOOL swap = (from_ofs > to_ofs);

  if (from_ofs == to_ofs)
  {
      /* If cursor[0] is at the beginning of a run and cursor[1] at the end
         of the prev run then we need to swap. */
      if (editor->pCursors[0].nOffset < editor->pCursors[1].nOffset)
          swap = TRUE;
  }

  if (!swap)
  {
    *from = &editor->pCursors[0];
    *to = &editor->pCursors[1];
    return 0;
  } else {
    *from = &editor->pCursors[1];
    *to = &editor->pCursors[0];
    return 1;
  }
}
Пример #2
0
void ME_TabPressedInTable(ME_TextEditor *editor, BOOL bSelectedRow)
{
    /* FIXME: Shift tab should move to the previous cell. */
    ME_Cursor fromCursor, toCursor;
    ME_InvalidateSelection(editor);
    {
        int from, to;
        from = ME_GetCursorOfs(editor, 0);
        to = ME_GetCursorOfs(editor, 1);
        if (from <= to)
        {
            fromCursor = editor->pCursors[0];
            toCursor = editor->pCursors[1];
        } else {
            fromCursor = editor->pCursors[1];
            toCursor = editor->pCursors[0];
        }
    }
    if (!editor->bEmulateVersion10) /* v4.1 */
    {
        if (!ME_IsInTable(toCursor.pRun))
        {
            editor->pCursors[0] = toCursor;
            editor->pCursors[1] = toCursor;
        } else {
            ME_SelectOrInsertNextCell(editor, toCursor.pRun);
        }
    } else { /* v1.0 - 3.0 */
        if (!ME_IsInTable(fromCursor.pRun)) {
            editor->pCursors[0] = fromCursor;
            editor->pCursors[1] = fromCursor;
            /* FIXME: For some reason the caret is shown at the start of the
             *        previous paragraph in v1.0 to v3.0, and bCaretAtEnd only works
             *        within the paragraph for wrapped lines. */
            if (ME_FindItemBack(fromCursor.pRun, diRun))
                editor->bCaretAtEnd = TRUE;
        } else if ((bSelectedRow || !ME_IsInTable(toCursor.pRun))) {
            ME_SelectOrInsertNextCell(editor, fromCursor.pRun);
        } else {
            if (ME_IsSelection(editor) && !toCursor.nOffset)
            {
                ME_DisplayItem *run;
                run = ME_FindItemBack(toCursor.pRun, diRunOrParagraphOrEnd);
                if (run->type == diRun && run->member.run.nFlags & MERF_TAB)
                    ME_SelectOrInsertNextCell(editor, run);
                else
                    ME_SelectOrInsertNextCell(editor, toCursor.pRun);
            } else {
                ME_SelectOrInsertNextCell(editor, toCursor.pRun);
            }
        }
    }
    ME_InvalidateSelection(editor);
    ME_Repaint(editor);
    HideCaret(editor->hWnd);
    ME_ShowCaret(editor);
    ME_SendSelChange(editor);
}
Пример #3
0
static int ME_GetSelCursor(ME_TextEditor *editor, int dir)
{
  int cdir = ME_GetCursorOfs(editor, 0) - ME_GetCursorOfs(editor, 1);
  
  if (cdir*dir>0)
    return 0;
  else
    return 1;
}
Пример #4
0
void ME_GetSelection(ME_TextEditor *editor, int *from, int *to)
{
  *from = ME_GetCursorOfs(editor, 0);
  *to =   ME_GetCursorOfs(editor, 1);
  
  if (*from > *to)
  {
    int tmp = *from;
    *from = *to;
    *to = tmp;    
  }
}
Пример #5
0
int ME_GetSelection(ME_TextEditor *editor, ME_Cursor **from, ME_Cursor **to)
{
  if (ME_GetCursorOfs(&editor->pCursors[0]) < ME_GetCursorOfs(&editor->pCursors[1]))
  {
    *from = &editor->pCursors[0];
    *to = &editor->pCursors[1];
    return 0;
  } else {
    *from = &editor->pCursors[1];
    *to = &editor->pCursors[0];
    return 1;
  }
}
Пример #6
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;
      }
  }
}
Пример #7
0
int ME_GetSelectionOfs(ME_TextEditor *editor, int *from, int *to)
{
  *from = ME_GetCursorOfs(&editor->pCursors[0]);
  *to =   ME_GetCursorOfs(&editor->pCursors[1]);

  if (*from > *to)
  {
    int tmp = *from;
    *from = *to;
    *to = tmp;
    return 1;
  }
  return 0;
}
Пример #8
0
HRESULT ME_GetDataObject(ME_TextEditor *editor, const ME_Cursor *start,
                         int nChars, LPDATAOBJECT *lplpdataobj)
{
    DataObjectImpl *obj;
    TRACE("(%p,%d,%d)\n", editor, ME_GetCursorOfs(start), nChars);

    obj = heap_alloc(sizeof(DataObjectImpl));
    if(cfRTF == 0)
        cfRTF = RegisterClipboardFormatA("Rich Text Format");

    obj->IDataObject_iface.lpVtbl = &VT_DataObjectImpl;
    obj->ref = 1;
    obj->unicode = get_unicode_text(editor, start, nChars);
    obj->rtf = NULL;

    obj->fmtetc_cnt = 1;
    if(editor->mode & TM_RICHTEXT)
        obj->fmtetc_cnt++;
    obj->fmtetc = GlobalAlloc(GMEM_ZEROINIT, obj->fmtetc_cnt*sizeof(FORMATETC));
    InitFormatEtc(obj->fmtetc[0], CF_UNICODETEXT, TYMED_HGLOBAL);
    if(editor->mode & TM_RICHTEXT) {
        obj->rtf = get_rtf_text(editor, start, nChars);
        InitFormatEtc(obj->fmtetc[1], cfRTF, TYMED_HGLOBAL);
    }

    *lplpdataobj = (LPDATAOBJECT)obj;
    return S_OK;
}
Пример #9
0
BOOL ME_DeleteTextAtCursor(ME_TextEditor *editor, int nCursor, int nChars)
{  
  assert(nCursor>=0 && nCursor<editor->nCursors);
  /* text operations set modified state */
  editor->nModifyStep = 1;
  return ME_InternalDeleteText(editor, ME_GetCursorOfs(editor, nCursor), nChars,
                               FALSE);
}
Пример #10
0
static HGLOBAL get_unicode_text(ME_TextEditor *editor, const ME_Cursor *start, int nChars)
{
    int pars = 0;
    WCHAR *data;
    HANDLE ret;
    ME_DisplayItem *para;
    int nEnd = ME_GetCursorOfs(start) + nChars;

    /* count paragraphs in range */
    para = start->pPara;
    while((para = para->member.para.next_para) &&
          para->member.para.nCharOfs <= nEnd)
        pars++;

    ret = GlobalAlloc(GMEM_MOVEABLE, sizeof(WCHAR) * (nChars + pars + 1));
    data = GlobalLock(ret);
    ME_GetTextW(editor, data, nChars + pars, start, nChars, TRUE, FALSE);
    GlobalUnlock(ret);
    return ret;
}
Пример #11
0
int ME_GetTextLength(ME_TextEditor *editor)
{
  ME_Cursor cursor;
  ME_SetCursorToEnd(editor, &cursor);
  return ME_GetCursorOfs(&cursor);
}
Пример #12
0
/* Move the cursor nRelOfs characters (either forwards or backwards)
 *
 * returns the actual number of characters moved.
 **/
int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
{
  cursor->nOffset += nRelOfs;
  if (cursor->nOffset < 0)
  {
    cursor->nOffset += cursor->pRun->member.run.nCharOfs;
    if (cursor->nOffset >= 0)
    {
      /* new offset in the same paragraph */
      do {
        cursor->pRun = ME_FindItemBack(cursor->pRun, diRun);
      } while (cursor->nOffset < cursor->pRun->member.run.nCharOfs);
      cursor->nOffset -= cursor->pRun->member.run.nCharOfs;
      return nRelOfs;
    }

    cursor->nOffset += cursor->pPara->member.para.nCharOfs;
    if (cursor->nOffset <= 0)
    {
      /* moved to the start of the text */
      nRelOfs -= cursor->nOffset;
      ME_SetCursorToStart(editor, cursor);
      return nRelOfs;
    }

    /* new offset in a previous paragraph */
    do {
      cursor->pPara = cursor->pPara->member.para.prev_para;
    } while (cursor->nOffset < cursor->pPara->member.para.nCharOfs);
    cursor->nOffset -= cursor->pPara->member.para.nCharOfs;

    cursor->pRun = ME_FindItemBack(cursor->pPara->member.para.next_para, diRun);
    while (cursor->nOffset < cursor->pRun->member.run.nCharOfs) {
      cursor->pRun = ME_FindItemBack(cursor->pRun, diRun);
    }
    cursor->nOffset -= cursor->pRun->member.run.nCharOfs;
  } else if (cursor->nOffset >= cursor->pRun->member.run.len) {
    ME_DisplayItem *next_para;
    int new_offset;

    new_offset = ME_GetCursorOfs(cursor);
    next_para = cursor->pPara->member.para.next_para;
    if (new_offset < next_para->member.para.nCharOfs)
    {
      /* new offset in the same paragraph */
      do {
        cursor->nOffset -= cursor->pRun->member.run.len;
        cursor->pRun = ME_FindItemFwd(cursor->pRun, diRun);
      } while (cursor->nOffset >= cursor->pRun->member.run.len);
      return nRelOfs;
    }

    if (new_offset >= ME_GetTextLength(editor))
    {
      /* new offset at the end of the text */
      ME_SetCursorToEnd(editor, cursor);
      nRelOfs -= new_offset - ME_GetTextLength(editor);
      return nRelOfs;
    }

    /* new offset in a following paragraph */
    do {
      cursor->pPara = next_para;
      next_para = next_para->member.para.next_para;
    } while (new_offset >= next_para->member.para.nCharOfs);

    cursor->nOffset = new_offset - cursor->pPara->member.para.nCharOfs;
    cursor->pRun = ME_FindItemFwd(cursor->pPara, diRun);
    while (cursor->nOffset >= cursor->pRun->member.run.len)
    {
      cursor->nOffset -= cursor->pRun->member.run.len;
      cursor->pRun = ME_FindItemFwd(cursor->pRun, diRun);
    }
  } /* else new offset is in the same run */
  return nRelOfs;
}
Пример #13
0
BOOL ME_InternalDeleteText(ME_TextEditor *editor, ME_Cursor *start,
                           int nChars, BOOL bForce)
{
  ME_Cursor c = *start;
  int nOfs = ME_GetCursorOfs(start), text_len = ME_GetTextLength( editor );
  int shift = 0;
  int totalChars = nChars;
  ME_DisplayItem *start_para;
  BOOL delete_all = FALSE;

  /* Prevent deletion past last end of paragraph run. */
  nChars = min(nChars, text_len - nOfs);
  if (nChars == text_len) delete_all = TRUE;
  start_para = c.pPara;

  if (!bForce)
  {
    ME_ProtectPartialTableDeletion(editor, &c, &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
                        + c.pPara->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. */
      ME_PrevRun(&c.pPara, &c.pRun);
      c.nOffset = c.pRun->member.run.len;
    }
    run = &c.pRun->member.run;
    if (run->nFlags & MERF_ENDPARA) {
      int eollen = c.pRun->member.run.len;
      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, c.pPara, 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_run( run ), run->len);

      /* nOfs is a character offset (from the start of the document
         to the current (deleted) run */
      add_undo_insert_run( editor, nOfs + nChars, get_text( run, c.nOffset ), nCharsToDelete, run->nFlags, run->style );

      ME_StrDeleteV(run->para->text, run->nCharOfs + c.nOffset, nCharsToDelete);
      run->len -= nCharsToDelete;
      TRACE("Post deletion string: %s (%d)\n", debugstr_run( run ), run->len);
      TRACE("Shift value: %d\n", shift);

      /* 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 <= run->len);
          }
          if (pThisCur->nOffset == run->len)
          {
            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 (!cursor.pRun->member.run.len)
      {
        TRACE("Removing empty run\n");
        ME_Remove(cursor.pRun);
        ME_DestroyDisplayItem(cursor.pRun);
      }

      shift = 0;
      /*
      ME_CheckCharOffsets(editor);
      */
      continue;
    }
  }
  if (delete_all) ME_SetDefaultParaFormat( editor, start_para->member.para.pFmt );
  return TRUE;
}
Пример #14
0
void ME_DeleteTextAtCursor(ME_TextEditor *editor, int nCursor, 
  int nChars)
{  
  assert(nCursor>=0 && nCursor<editor->nCursors);
  ME_InternalDeleteText(editor, ME_GetCursorOfs(editor, nCursor), nChars);
}
Пример #15
0
/* Table rows should either be deleted completely or not at all. */
void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, ME_Cursor *c, int *nChars)
{
  int nOfs = ME_GetCursorOfs(c);
  ME_Cursor c2 = *c;
  ME_DisplayItem *this_para = c->pPara;
  ME_DisplayItem *end_para;

  ME_MoveCursorChars(editor, &c2, *nChars);
  end_para = c2.pPara;
  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.len);
      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->len);
          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. */
      ME_DisplayItem *curPara;
      pRun = NULL;
      if (nOfs > this_para->member.para.nCharOfs) {
        pRun = ME_FindItemBack(end_para, diRun);
        curPara = end_para->member.para.prev_para;
      }
      if (!pRun) {
        pRun = ME_FindItemFwd(end_para, diRun);
        curPara = end_para;
      }
      if (pRun)
      {
        nCharsToBoundary = curPara->member.para.nCharOfs
                           + pRun->member.run.nCharOfs
                           - nOfs;
        if (nCharsToBoundary >= 0)
          *nChars = min(*nChars, nCharsToBoundary);
      }
    }
    if (*nChars < 0)
      nChars = 0;
  }
}
Пример #16
0
void
ME_QueueInvalidateFromCursor(ME_TextEditor *editor, int nCursor)
{
  editor->nInvalidOfs = ME_GetCursorOfs(editor, nCursor);
}