⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 editor.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:
  {
    ME_DisplayItem *para;
    
    RTFFlushOutputBuffer(info);
    para = ME_GetParagraph(info->editor->pCursors[0].pRun);
    assert(para->member.para.pCells);
    para->member.para.bTable = TRUE;
    return;
  }
  case rtfFirstIndent:
    ME_GetSelectionParaFormat(info->editor, &fmt);
    fmt.dwMask = PFM_STARTINDENT | PFM_OFFSET;
    fmt.dxStartIndent += info->rtfParam + fmt.dxOffset;
    fmt.dxOffset = -info->rtfParam;
    break;
  case rtfLeftIndent:
    ME_GetSelectionParaFormat(info->editor, &fmt);
    fmt.dwMask = PFM_STARTINDENT;
    fmt.dxStartIndent = -fmt.dxOffset + info->rtfParam;
    break;
  case rtfRightIndent:
    fmt.dwMask = PFM_RIGHTINDENT;
    fmt.dxRightIndent = info->rtfParam;
    break;
  case rtfQuadLeft:
  case rtfQuadJust:
    fmt.dwMask = PFM_ALIGNMENT;
    fmt.wAlignment = PFA_LEFT;
    break;
  case rtfQuadRight:
    fmt.dwMask = PFM_ALIGNMENT;
    fmt.wAlignment = PFA_RIGHT;
    break;
  case rtfQuadCenter:
    fmt.dwMask = PFM_ALIGNMENT;
    fmt.wAlignment = PFA_CENTER;
    break;
  case rtfTabPos:
    ME_GetSelectionParaFormat(info->editor, &fmt);
    if (!(fmt.dwMask & PFM_TABSTOPS))
    {
      fmt.dwMask |= PFM_TABSTOPS;
      fmt.cTabCount = 0;
    }
    if (fmt.cTabCount < MAX_TAB_STOPS)
      fmt.rgxTabs[fmt.cTabCount++] = info->rtfParam;
    break;
  }  
  if (fmt.dwMask) {
    RTFFlushOutputBuffer(info);
    /* FIXME too slow ? how come ?*/
    ME_SetSelectionParaFormat(info->editor, &fmt);
  }
}

static void ME_RTFTblAttrHook(RTF_Info *info)
{
  ME_DisplayItem *para;
  
  switch (info->rtfMinor)
  {
    case rtfRowDef:
      RTFFlushOutputBuffer(info);
      para = ME_GetParagraph(info->editor->pCursors[0].pRun);
      
      /* Release possibly inherited cell definitions */
      ME_DestroyTableCellList(para);
      
      para->member.para.pCells = ALLOC_OBJ(ME_TableCell);
      para->member.para.pCells->nRightBoundary = 0;
      para->member.para.pCells->next = NULL;
      para->member.para.pLastCell = para->member.para.pCells;
      break;
    case rtfCellPos:
      RTFFlushOutputBuffer(info);
      para = ME_GetParagraph(info->editor->pCursors[0].pRun);
      
      if (para->member.para.pLastCell->nRightBoundary)
      {
        ME_TableCell *pCell = ALLOC_OBJ(ME_TableCell);
        
        pCell->next = NULL;
        para->member.para.pLastCell->next = pCell;
        para->member.para.pLastCell = pCell;
      }
      para->member.para.pLastCell->nRightBoundary = info->rtfParam;
      break;
  }
}

static void ME_RTFReadHook(RTF_Info *info) {
  switch(info->rtfClass)
  {
    case rtfGroup:
      switch(info->rtfMajor)
      {
        case rtfBeginGroup:
          if (info->stackTop < maxStack) {
            memcpy(&info->stack[info->stackTop].fmt, &info->style->fmt, sizeof(CHARFORMAT2W));
            info->stack[info->stackTop].codePage = info->codePage;
            info->stack[info->stackTop].unicodeLength = info->unicodeLength;
          }
          info->stackTop++;
          info->styleChanged = FALSE;
          break;
        case rtfEndGroup:
        {
          ME_Style *s;
          RTFFlushOutputBuffer(info);
          if (info->stackTop<=1) {
            info->rtfClass = rtfEOF;
            return;
          }
          info->stackTop--;
          assert(info->stackTop >= 0);
          if (info->styleChanged)
          {
            /* FIXME too slow ? how come ? */
            s = ME_ApplyStyle(info->style, &info->stack[info->stackTop].fmt);
            ME_ReleaseStyle(info->style);
            info->style = s;
            info->codePage = info->stack[info->stackTop].codePage;
            info->unicodeLength = info->stack[info->stackTop].unicodeLength;
          }
          break;
        }
      }
      break;
    case rtfControl:
      switch(info->rtfMajor)
      {
        case rtfCharAttr:
          ME_RTFCharAttrHook(info);
          break;
        case rtfParAttr:
          ME_RTFParAttrHook(info);
          break;
        case rtfTblAttr:
          ME_RTFTblAttrHook(info);
          break;
        case rtfSpecialChar:
          if (info->rtfMinor == rtfCell)
          {
            RTFFlushOutputBuffer(info);
            ME_InsertTableCellFromCursor(info->editor, 0);
          }
      }
      break;
  }
}

void
ME_StreamInFill(ME_InStream *stream)
{
  stream->editstream->dwError = stream->editstream->pfnCallback(stream->editstream->dwCookie,
                                                                (BYTE *)stream->buffer,
                                                                sizeof(stream->buffer),
                                                                (LONG *)&stream->dwSize);
  stream->dwUsed = 0;
}

static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stream)
{
  RTF_Info parser;
  ME_Style *style;
  int from, to, to2, nUndoMode;
  int nEventMask = editor->nEventMask;
  ME_InStream inStream;

  TRACE("stream==%p hWnd==%p format==0x%X\n", stream, editor->hWnd, (UINT)format);
  editor->nEventMask = 0;
  
  ME_GetSelection(editor, &from, &to);
  if ((format & SFF_SELECTION) && (editor->mode & TM_RICHTEXT)) {
    style = ME_GetSelectionInsertStyle(editor);

    ME_InternalDeleteText(editor, from, to-from);
  }
  else {
    style = editor->pBuffer->pDefaultStyle;
    ME_AddRefStyle(style);
    SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);    
    ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
    from = to = 0;
    ME_ClearTempStyle(editor);
    /* FIXME restore default paragraph formatting ! */
  }


  /* Back up undo mode to a local variable */
  nUndoMode = editor->nUndoMode;

  /* Only create an undo if SFF_SELECTION is set */
  if (!(format & SFF_SELECTION))
    editor->nUndoMode = umIgnore;

  inStream.editstream = stream;
  inStream.editstream->dwError = 0;
  inStream.dwSize = 0;
  inStream.dwUsed = 0;

  if (format & SF_RTF)
  {
    /* Check if it's really RTF, and if it is not, use plain text */
    ME_StreamInFill(&inStream);
    if (!inStream.editstream->dwError)
    {
      if (strncmp(inStream.buffer, "{\\rtf", 5) && strncmp(inStream.buffer, "{\\urtf", 6))
      {
        format &= ~SF_RTF;
        format |= SF_TEXT;
      }
    }
  }

  if (!inStream.editstream->dwError)
  {
    if (format & SF_RTF) {
      /* setup the RTF parser */
      memset(&parser, 0, sizeof parser);
      RTFSetEditStream(&parser, &inStream);
      parser.rtfFormat = format&(SF_TEXT|SF_RTF);
      parser.hwndEdit = editor->hWnd;
      parser.editor = editor;
      parser.style = style;
      WriterInit(&parser);
      RTFInit(&parser);
      RTFSetReadHook(&parser, ME_RTFReadHook);
      BeginFile(&parser);
  
      /* do the parsing */
      RTFRead(&parser);
      RTFFlushOutputBuffer(&parser);
      RTFDestroy(&parser);

      style = parser.style;
    }
    else if (format & SF_TEXT)
      ME_StreamInText(editor, format, &inStream, style);
    else
      ERR("EM_STREAMIN without SF_TEXT or SF_RTF\n");
    ME_GetSelection(editor, &to, &to2);
    /* put the cursor at the top */
    if (!(format & SFF_SELECTION))
      SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
  }

  /* Restore saved undo mode */
  editor->nUndoMode = nUndoMode;

  /* even if we didn't add an undo, we need to commit anything on the stack */
  ME_CommitUndo(editor);

  /* If SFF_SELECTION isn't set, delete any undos from before we started too */
  if (!(format & SFF_SELECTION))
    ME_EmptyUndoStack(editor);

  ME_ReleaseStyle(style);
  editor->nEventMask = nEventMask;
  if (editor->bRedraw)
  {
    ME_UpdateRepaint(editor);
  }
  if (!(format & SFF_SELECTION)) {
    ME_ClearTempStyle(editor);
  }
  ME_MoveCaret(editor);
  ME_SendSelChange(editor);
  ME_SendRequestResize(editor, FALSE);

  return 0;
}


typedef struct tagME_RTFStringStreamStruct
{
  char *string;
  int pos;
  int length;
} ME_RTFStringStreamStruct;

static DWORD CALLBACK ME_ReadFromRTFString(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb)
{
  ME_RTFStringStreamStruct *pStruct = (ME_RTFStringStreamStruct *)dwCookie;
  int count;

  count = min(cb, pStruct->length - pStruct->pos);
  memmove(lpBuff, pStruct->string + pStruct->pos, count);
  pStruct->pos += count;
  *pcb = count;
  return 0;
}

static void
ME_StreamInRTFString(ME_TextEditor *editor, BOOL selection, char *string)
{
  EDITSTREAM es;
  ME_RTFStringStreamStruct data;

  data.string = string;
  data.length = strlen(string);
  data.pos = 0;
  es.dwCookie = (DWORD)&data;
  es.pfnCallback = ME_ReadFromRTFString;
  ME_StreamIn(editor, SF_RTF | (selection ? SFF_SELECTION : 0), &es);
}


ME_DisplayItem *
ME_FindItemAtOffset(ME_TextEditor *editor, ME_DIType nItemType, int nOffset, int *nItemOffset)
{
  ME_DisplayItem *item = ME_FindItemFwd(editor->pBuffer->pFirst, diParagraph);
  
  while (item && item->member.para.next_para->member.para.nCharOfs <= nOffset)
    item = ME_FindItemFwd(item, diParagraph);

  if (!item)
    return item;

  nOffset -= item->member.para.nCharOfs;
  if (nItemType == diParagraph) {
    if (nItemOffset)
      *nItemOffset = nOffset;
    return item;
  }
  
  do {
    item = ME_FindItemFwd(item, diRun);
  } while (item && (item->member.run.nCharOfs + ME_StrLen(item->member.run.strText) <= nOffset));
  if (item) {
    nOffset -= item->member.run.nCharOfs;
    if (nItemOffset)
      *nItemOffset = nOffset;
  }
  return item;
}


static int
ME_FindText(ME_TextEditor *editor, DWORD flags, CHARRANGE *chrg, const WCHAR *text, CHARRANGE *chrgText)
{
  const int nLen = lstrlenW(text);
  const int nTextLen = ME_GetTextLength(editor);
  int nStart, nEnd;
  int nMin, nMax;
  ME_DisplayItem *item;
  ME_DisplayItem *para;
  WCHAR wLastChar = ' ';

  TRACE("flags==0x%08x, chrg->cpMin==%d, chrg->cpMax==%d text==%s\n",
        flags, chrg->cpMin, chrg->cpMax, debugstr_w(text));
  
  if (flags & ~(FR_DOWN | FR_MATCHCASE | FR_WHOLEWORD))
    FIXME("Flags 0x%08x not implemented\n",
        flags & ~(FR_DOWN | FR_MATCHCASE | FR_WHOLEWORD));

  nMin = chrg->cpMin;
  if (chrg->cpMax == -1)
    nMax = nTextLen;
  else
    nMax = chrg->cpMax > nTextLen ? nTextLen : chrg->cpMax;
  
  /* when searching up, if cpMin < cpMax, then instead of searching
   * on [cpMin,cpMax], we search on [0,cpMin], otherwise, search on
   * [cpMax, cpMin]. The exception is when cpMax is -1, in which
   * case, it is always bigger than cpMin.
   */
  if (!(flags & FR_DOWN))
  {
    int nSwap = nMax;

    nMax = nMin > nTextLen ? nTextLen : nMin;
    if (nMin < nSwap || chrg->cpMax == -1)
      nMin = 0;
    else
      nMin = nSwap;
  }

  if (!nLen || nMin < 0 || nMax < 0 || nMax < nMin)
  {
    if (chrgText)
      chrgText->cpMin = chrgText->cpMax = -1;
    return -1;
  }
 
  if (flags & FR_DOWN) /* Forward search */
  {
    /* If possible, find the character before where the search starts */
    if ((flags & FR_WHOLEWORD) && nMin)
    {
      nStart = nMin - 1;
      item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart);
      if (!item)
      {
        if (chrgText)
          chrgText->cpMin = chrgText->cpMax = -1;
        return -1;
      }
      wLastChar = item->member.run.strText->szData[nStart];
    }

    nStart = nMin;
    item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart);
    if (!item)
    {
      if (chrgText)
        chrgText->cpMin = chrgText->cpMax = -1;
      return -1;
    }

    para = ME_GetParagraph(item);
    while (item
           && para->member.para.nCharOfs + item->member.run.nCharOfs + nStart + nLen <= nMax)
    {
      ME_DisplayItem *pCurItem = item;
      int nCurStart = nStart;
      int nMatched = 0;
    
      while (pCurItem && ME_CharCompare(pCurItem->member.run.strText->szData[nCurStart + nMatched], text[nMatched], (flags & FR_MATCHCASE)))
      {
        if ((flags & FR_WHOLEWORD) && isalnumW(wLastChar))
          break;

        nMatched++;
        if (nMatched == nLen)
        {
          ME_DisplayItem *pNextItem = pCurItem;
          int nNextStart = nCurStart;
          WCHAR wNextChar;

          /* Check to see if next character is a whitespace */
          if (flags & FR_WHOLEWORD)
          {
            if (nCurStart + nMatched == ME_StrLen(pCurItem->member.run.strText))
            {
              pNextItem = ME_FindItemFwd(pCurItem, diRun);
              nNextStart = -nMatched;
            }

            if (pNextItem)
              wNextChar = pNextItem->member.run.strText->szData[nNextStart + nMatched];
            else
              wNextChar = ' ';

            if (isalnumW(wNextChar))

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -