mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
Sync to Wine-20050419:
Krzysztof Foltman <wdev@foltman.com> - removed trailing spaces from some files - tab support - indent support - PageUp key support. - Support for "normal" scroll bar functionality (line and page scrolling). - made string operations consistent wrt whitespace handling (which should greatly improve stability of the wrap code and eliminate regressions of the most recent versions) - completely new scrollbar handling (much more reliable) and related redraw fixes - Page Down handler (no Page Up yet, fixing wrap/redraw/scrollbar bugs was of higher priority) - RTF reader doesn't use RichEdit messages anymore (which saves on unnecessary repaints) - added unicode character support to RTF import (like: \u12345 ?) - small fixes - fixed whitespace identification bug - removed drawing of paragraph marks - improved stub implementations for IRichEditOle - Unknown destinations are now correctly skipped (so loading an RTF file generated by, for example, OpenOffice doesn't produce lots of garbage anymore). - Format stack for RTF groups (so that RTF reader can correctly read what RTF writer wrote :) ) - EM_STREAMIN can now deal with undo in a reasonable manner (no multiple undo actions in one EM_STREAMIN). - Related changes to undo code (umIgnore mode is now handled correctly). - Numerous improvements in the RTF reader: it reads some character attributes now (you will have proper small print in license agreements now). - Fixed a memory overwrite bug in conversion from CHARFORMAT2A to CHARFORMAT2W. - Optimized repaint of the area below the text. - ME_JoinRuns didn't mark the paragraph for rewrapping, fixed. - Removed PostQuitMessage(0) from WM_DESTROY handler (duh!). - Use of EM_GETOLEINTERFACE is reported with FIXME instead of TRACE (any app using this message is likely to encounter major problems). - WM_COPY (and WM_CUT) can now put both Unicode and RTF format (thanks to Phil Krylov's RTF generator code). - New message implemented - WM_PASTE. - RTF reader: rtfPlain implemented (kind of). - RTF writer: rewritten main loop (the old one crashed in some circumstances when SFF_SELECTION was used). - The meaning of the rewrap flag got inverted (MEPF_REWRAP instead of MEPF_WRAPPED) for consistency. - Major code cleanups in rewrap/repaint code, leading to "smarter" behaviour wrt repainting selections. - Old font management replaced by the cache-based one, which keeps maximum of 10 HFONTs at once, instead of one per a couple of runs. - EM_CANPASTE implemented - updated TODO list (including list of (un)implemented messages) - fixed WM_PASTE (the previous version might not close the clipboard if it didn't contain a usable format) - scrollbar operations (like clicking on arrows) should update scrollbar's current position Gerald Pfeifer <gerald@pfeifer.com> - Make ME_ArrowLeft() return a value in every case. Phil Krylov <phil@newstar.rinet.ru> - Make RTF reader fall back to simple text if a correct RTF header is not detected. This should fix some installers. - Made RTF reader and writer handle codepages mostly similar to the original riched20.dll. - Fixed support for RTF documents using ANSI charset and added support for multibyte charsets, so that BIG5 and UTF-8 RTF documents are working now. - Replaced slow and outdated character set handling in RTF reader by Unicode/codepages support. Added charset->codepage conversion. - Implemented hash table lookup for RTF keywords in RTF reader. - Added "generator" RTF destination handling. - Initial implementation of EM_STREAMOUT and RTF writer. - Fixed \u keyword to output signed 16-bit values. Also fixed CP_SYMBOL conversion and the detection of the default font's codepage. - Improved RTF export. Mike McCormack <mike@codeweavers.com> - Remove casts and unused code. Hannu Valtonen <Hannu.Valtonen@hut.fi> - Added mousewheel support. Vincent Beron <vberon@mecano.gme.usherb.ca> - Use "" for Windows includes in dlls, instead of <>. Jakob Eriksson <jakov@vmlinux.org> - Get rid of HeapAlloc casts. Jason Edmeades <us@the-edmeades.demon.co.uk> - Correct memory allocation macro. svn path=/trunk/; revision=15014
This commit is contained in:
parent
f71087e736
commit
e14533d20a
17 changed files with 2399 additions and 2272 deletions
|
@ -20,7 +20,8 @@ C_SRCS = \
|
|||
string.c \
|
||||
style.c \
|
||||
undo.c \
|
||||
wrap.c
|
||||
wrap.c \
|
||||
writer.c
|
||||
|
||||
@MAKE_DLL_RULES@
|
||||
|
||||
|
|
|
@ -104,15 +104,15 @@ void ME_MoveCaret(ME_TextEditor *editor)
|
|||
{
|
||||
row = ME_FindItemBack(tmp, diStartRow);
|
||||
pSizeRun = run = tmp;
|
||||
sz = ME_GetRunSize(&c, &run->member.run, ME_StrLen(run->member.run.strText));
|
||||
sz = ME_GetRunSize(&c, ¶->member.para, &run->member.run, ME_StrLen(run->member.run.strText));
|
||||
}
|
||||
}
|
||||
if (pCursor->nOffset && !(run->member.run.nFlags & MERF_SKIPPED)) {
|
||||
sz = ME_GetRunSize(&c, &run->member.run, pCursor->nOffset);
|
||||
sz = ME_GetRunSize(&c, ¶->member.para, &run->member.run, pCursor->nOffset);
|
||||
}
|
||||
CreateCaret(editor->hWnd, NULL, 0, pSizeRun->member.run.nAscent+pSizeRun->member.run.nDescent);
|
||||
SetCaretPos(run->member.run.pt.x+sz.cx,
|
||||
para->member.para.nYPos+row->member.row.nBaseline+pSizeRun->member.run.pt.y-pSizeRun->member.run.nAscent-GetScrollPos(editor->hWnd, SB_VERT));
|
||||
para->member.para.nYPos+row->member.row.nBaseline+pSizeRun->member.run.pt.y-pSizeRun->member.run.nAscent-ME_GetYScrollPos(editor));
|
||||
} else {
|
||||
assert(0 == "Wrapped paragraph run without a row?");
|
||||
CreateCaret(editor->hWnd, NULL, 0, 10);
|
||||
|
@ -300,12 +300,6 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
|
|||
assert(style);
|
||||
editor->bCaretAtEnd = FALSE;
|
||||
|
||||
/*
|
||||
if (!style)
|
||||
style = ME_GetInsertStyle(editor, nCursor);
|
||||
else
|
||||
ME_AddRefStyle(style);
|
||||
*/
|
||||
ME_AddRefStyle(style);
|
||||
|
||||
/* FIXME really HERE ? */
|
||||
|
@ -317,10 +311,30 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
|
|||
len = lstrlenW(str);
|
||||
pos = str;
|
||||
/* FIXME this sucks - no respect for unicode (what else can be a line separator in unicode?) */
|
||||
while(pos-str < len && *pos != '\r' && *pos != '\n')
|
||||
while(pos-str < len && *pos != '\r' && *pos != '\n' && *pos != '\t')
|
||||
pos++;
|
||||
/* handle EOLs */
|
||||
if (pos-str < len) {
|
||||
if (pos-str < len && *pos == '\t') { /* handle tabs */
|
||||
ME_DisplayItem *pNewRun = NULL;
|
||||
WCHAR tab = '\t';
|
||||
|
||||
if (pos!=str)
|
||||
ME_InsertTextFromCursor(editor, nCursor, str, pos-str, style);
|
||||
|
||||
p = &editor->pCursors[nCursor];
|
||||
assert(style);
|
||||
assert(p->pRun->type == diRun);
|
||||
pNewRun = ME_MakeRun(style, ME_MakeStringN(&tab, 1), MERF_TAB); /* addrefs style */
|
||||
ME_InsertRun(editor, ME_CharOfsFromRunOfs(editor, p->pRun, p->nOffset), pNewRun);
|
||||
ME_DestroyDisplayItem(pNewRun);
|
||||
ME_ReleaseStyle(style);
|
||||
|
||||
pos++;
|
||||
if(pos-str < len) {
|
||||
ME_InsertTextFromCursor(editor, nCursor, pos, len-(pos-str), style);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (pos-str < len) { /* handle EOLs */
|
||||
ME_DisplayItem *tp, *end_run;
|
||||
ME_Paragraph *para;
|
||||
ME_Style *tmp_style;
|
||||
|
@ -404,6 +418,7 @@ BOOL ME_ArrowLeft(ME_TextEditor *editor, ME_Cursor *p)
|
|||
}
|
||||
assert(0);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL ME_ArrowRight(ME_TextEditor *editor, ME_Cursor *p)
|
||||
|
@ -537,7 +552,7 @@ void ME_LButtonDown(ME_TextEditor *editor, int x, int y)
|
|||
|
||||
editor->nUDArrowX = -1;
|
||||
|
||||
y += GetScrollPos(editor->hWnd, SB_VERT);
|
||||
y += ME_GetYScrollPos(editor);
|
||||
|
||||
tmp_cursor = editor->pCursors[0];
|
||||
is_selection = ME_IsSelection(editor);
|
||||
|
@ -568,7 +583,7 @@ void ME_MouseMove(ME_TextEditor *editor, int x, int y)
|
|||
{
|
||||
ME_Cursor tmp_cursor;
|
||||
|
||||
y += GetScrollPos(editor->hWnd, SB_VERT);
|
||||
y += ME_GetYScrollPos(editor);
|
||||
|
||||
tmp_cursor = editor->pCursors[0];
|
||||
if (!ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd))
|
||||
|
@ -702,6 +717,109 @@ void ME_ArrowDown(ME_TextEditor *editor, ME_Cursor *pCursor)
|
|||
assert(pCursor->pRun->type == diRun);
|
||||
}
|
||||
|
||||
void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
|
||||
{
|
||||
ME_DisplayItem *pRun = pCursor->pRun;
|
||||
ME_DisplayItem *pLast, *p;
|
||||
int x, y, ys, yd, yp, yprev;
|
||||
ME_Cursor tmp_curs = *pCursor;
|
||||
|
||||
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.nYPos;
|
||||
yprev = ys = y = yp + p->member.row.nYPos;
|
||||
yd = y - editor->sizeWindow.cy;
|
||||
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.nYPos;
|
||||
continue;
|
||||
}
|
||||
y = yp + p->member.row.nYPos;
|
||||
if (y < yd)
|
||||
break;
|
||||
pLast = p;
|
||||
yprev = y;
|
||||
} while(1);
|
||||
|
||||
pCursor->pRun = ME_FindRunInRow(editor, pLast, x, &pCursor->nOffset, &editor->bCaretAtEnd);
|
||||
ME_UpdateSelection(editor, &tmp_curs);
|
||||
if (yprev < editor->sizeWindow.cy)
|
||||
{
|
||||
ME_EnsureVisible(editor, ME_FindItemFwd(editor->pBuffer->pFirst, diRun));
|
||||
ME_Repaint(editor);
|
||||
}
|
||||
else {
|
||||
ME_Scroll(editor, 0, ys-yprev);
|
||||
ME_Repaint(editor);
|
||||
}
|
||||
assert(pCursor->pRun);
|
||||
assert(pCursor->pRun->type == diRun);
|
||||
}
|
||||
|
||||
/* FIXME: in the original RICHEDIT, PageDown always scrolls by the same amount
|
||||
of pixels, even if it makes the scroll bar position exceed its normal maximum.
|
||||
In such a situation, clicking the scrollbar restores its position back to the
|
||||
normal range (ie. sets it to (doclength-screenheight)). */
|
||||
|
||||
void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
|
||||
{
|
||||
ME_DisplayItem *pRun = pCursor->pRun;
|
||||
ME_DisplayItem *pLast, *p;
|
||||
int x, y, ys, yd, yp, yprev;
|
||||
ME_Cursor tmp_curs = *pCursor;
|
||||
|
||||
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.nYPos;
|
||||
yprev = ys = y = yp + p->member.row.nYPos;
|
||||
yd = y + editor->sizeWindow.cy;
|
||||
pLast = p;
|
||||
|
||||
do {
|
||||
p = ME_FindItemFwd(p, diStartRowOrParagraph);
|
||||
if (!p)
|
||||
break;
|
||||
if (p->type == diParagraph) {
|
||||
yp = p->member.para.nYPos;
|
||||
continue;
|
||||
}
|
||||
y = yp + p->member.row.nYPos;
|
||||
if (y >= yd)
|
||||
break;
|
||||
pLast = p;
|
||||
yprev = y;
|
||||
} while(1);
|
||||
|
||||
pCursor->pRun = ME_FindRunInRow(editor, pLast, x, &pCursor->nOffset, &editor->bCaretAtEnd);
|
||||
ME_UpdateSelection(editor, &tmp_curs);
|
||||
if (yprev >= editor->nTotalLength-editor->sizeWindow.cy)
|
||||
{
|
||||
ME_EnsureVisible(editor, ME_FindItemBack(editor->pBuffer->pLast, diRun));
|
||||
ME_Repaint(editor);
|
||||
}
|
||||
else {
|
||||
ME_Scroll(editor, 0, ys-yprev);
|
||||
ME_Repaint(editor);
|
||||
}
|
||||
assert(pCursor->pRun);
|
||||
assert(pCursor->pRun->type == diRun);
|
||||
}
|
||||
|
||||
void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
|
||||
{
|
||||
ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diStartRow);
|
||||
|
@ -799,43 +917,42 @@ BOOL ME_CancelSelection(ME_TextEditor *editor, int dir)
|
|||
editor->pCursors[1] = editor->pCursors[0];
|
||||
else
|
||||
editor->pCursors[0] = editor->pCursors[1];
|
||||
/* FIXME optimize */
|
||||
ME_MarkAllForWrapping(editor);
|
||||
ME_Repaint(editor);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void ME_RepaintSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
|
||||
BOOL ME_UpdateSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
|
||||
{
|
||||
ME_Cursor old_anchor = editor->pCursors[1];
|
||||
BOOL bRedraw = FALSE;
|
||||
bRedraw = memcmp(&editor->pCursors[0], &editor->pCursors[1], sizeof(ME_Cursor));
|
||||
|
||||
if (bRedraw)
|
||||
{
|
||||
/* FIXME optimize */
|
||||
ME_MarkAllForWrapping(editor);
|
||||
}
|
||||
|
||||
if (GetKeyState(VK_SHIFT)>=0) /* cancelling selection */
|
||||
{
|
||||
/* any selection was present ? if so, it's no more, repaint ! */
|
||||
editor->pCursors[1] = editor->pCursors[0];
|
||||
if (memcmp(pTempCursor, &old_anchor, sizeof(ME_Cursor))) {
|
||||
ME_Repaint(editor);
|
||||
return;
|
||||
return TRUE;
|
||||
}
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!memcmp(pTempCursor, &editor->pCursors[1], sizeof(ME_Cursor))) /* starting selection */
|
||||
{
|
||||
editor->pCursors[1] = *pTempCursor;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
ME_Repaint(editor);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void ME_RepaintSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
|
||||
{
|
||||
if (ME_UpdateSelection(editor, pTempCursor)) {
|
||||
ME_EnsureVisible(editor, editor->pCursors[0].pRun);
|
||||
ME_Repaint(editor);
|
||||
}
|
||||
}
|
||||
|
||||
void ME_DeleteSelection(ME_TextEditor *editor)
|
||||
|
@ -898,6 +1015,16 @@ BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, int nCtrl)
|
|||
ME_RepaintSelection(editor, &tmp_curs);
|
||||
ME_SendSelChange(editor);
|
||||
return TRUE;
|
||||
case VK_PRIOR:
|
||||
ME_ArrowPageUp(editor, p);
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_SendSelChange(editor);
|
||||
return TRUE;
|
||||
case VK_NEXT:
|
||||
ME_ArrowPageDown(editor, p);
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_SendSelChange(editor);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
editor->nUDArrowX = -1;
|
||||
|
@ -914,6 +1041,7 @@ BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, int nCtrl)
|
|||
}
|
||||
if (ME_ArrowLeft(editor, p)) {
|
||||
editor->bCaretAtEnd = FALSE; /* FIXME or maybe not */
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_MoveCaret(editor);
|
||||
ME_DeleteTextAtCursor(editor, nCursor, 1);
|
||||
ME_UpdateRepaint(editor);
|
||||
|
@ -927,10 +1055,12 @@ BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, int nCtrl)
|
|||
if (ME_IsSelection(editor))
|
||||
{
|
||||
ME_DeleteSelection(editor);
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_UpdateRepaint(editor);
|
||||
return TRUE;
|
||||
}
|
||||
ME_DeleteTextAtCursor(editor, nCursor, 1);
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_UpdateRepaint(editor);
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
Messages (ANSI versions not done yet)
|
||||
- EM_AUTOURLDETECT 2.0
|
||||
- EM_CANPASTE
|
||||
+ EM_CANPASTE
|
||||
+ EM_CANREDO 2.0
|
||||
+ EM_CANUNDO
|
||||
- EM_CHARFROMPOS
|
||||
|
@ -73,7 +73,7 @@
|
|||
- EM_LINESCROLL
|
||||
- EM_PASTESPECIAL
|
||||
- EM_POSFROMCHARS
|
||||
- EM_REDO 2.0
|
||||
+ EM_REDO 2.0
|
||||
- EM_REQUESTRESIZE
|
||||
+ EM_REPLACESEL (proper style?) ANSI&Unicode
|
||||
- EM_SCROLL
|
||||
|
@ -102,17 +102,17 @@
|
|||
- EM_SETWORDBREAKPROCEX
|
||||
- EM_SETWORDWRAPMODE 1.0asian
|
||||
- EM_STOPGROUPTYPING 2.0
|
||||
- EM_STREAMIN
|
||||
- EM_STREAMOUT
|
||||
- EM_UNDO
|
||||
+ EM_STREAMIN (can't fall back to text when the RTF isn't really RTF)
|
||||
+ EM_STREAMOUT
|
||||
+ EM_UNDO
|
||||
+ WM_CHAR
|
||||
+ WM_CLEAR
|
||||
- WM_COPY (lame implementation, no RTF support)
|
||||
- WM_CUT (lame implementation, no RTF support)
|
||||
+ WM_COPY
|
||||
+ WM_CUT
|
||||
+ WM_GETDLGCODE (the current implementation is incomplete)
|
||||
+ WM_GETTEXT (ANSI&Unicode)
|
||||
+ WM_GETTEXTLENGTH (ANSI version sucks)
|
||||
- WM_PASTE
|
||||
+ WM_PASTE
|
||||
- WM_SETFONT
|
||||
+ WM_SETTEXT (resets undo stack !) (proper style?) ANSI&Unicode
|
||||
- WM_STYLECHANGING
|
||||
|
@ -166,30 +166,25 @@
|
|||
/*
|
||||
* RICHED20 TODO (incomplete):
|
||||
*
|
||||
* - font caching
|
||||
* - messages/styles/notifications listed above
|
||||
* - Undo coalescing
|
||||
* - add remaining CHARFORMAT/PARAFORMAT fields
|
||||
* - right/center align should strip spaces from the beginning
|
||||
* - more advanced navigation (Ctrl-arrows, PageUp/PageDn)
|
||||
* - more advanced navigation (Ctrl-arrows)
|
||||
* - tabs
|
||||
* - pictures (not just smiling faces that lack API support ;-) )
|
||||
* - OLE objects
|
||||
* - pictures/OLE objects (not just smiling faces that lack API support ;-) )
|
||||
* - COM interface (looks like a major pain in the TODO list)
|
||||
* - calculate heights of pictures (half-done)
|
||||
* - EM_STREAMIN/EM_STREAMOUT
|
||||
* - horizontal scrolling (not even started)
|
||||
* - fix scrollbars and refresh (it sucks bigtime)
|
||||
* - hysteresis during wrapping (related to scrollbars appearing/disappearing)
|
||||
* - should remember maximum row width for wrap hysteresis
|
||||
* - find/replace
|
||||
* - how to implement EM_FORMATRANGE and EM_DISPLAYBAND ? (Mission Impossible)
|
||||
* - italic cursor with italic fonts
|
||||
* - italic caret with italic fonts
|
||||
* - IME
|
||||
* - most notifications aren't sent at all (the most important ones are)
|
||||
* - when should EN_SELCHANGE be sent after text change ? (before/after EN_UPDATE?)
|
||||
* - WM_SETTEXT may use wrong style (but I'm 80% sure it's OK)
|
||||
* - EM_GETCHARFORMAT with SCF_SELECTION may not behave 100% like in original (but very close)
|
||||
* - bugs in end-of-text handling (the gray bar) could get me in jail ;-)
|
||||
* - determination of row size
|
||||
* - end-of-paragraph marks should be of reasonable size
|
||||
*
|
||||
* Bugs that are probably fixed, but not so easy to verify:
|
||||
* - EN_UPDATE/EN_CHANGE are handled very incorrectly (should be OK now)
|
||||
|
@ -203,11 +198,11 @@
|
|||
*/
|
||||
|
||||
#include "editor.h"
|
||||
#include <ole2.h>
|
||||
#include <richole.h>
|
||||
#include <winreg.h>
|
||||
#include "ole2.h"
|
||||
#include "richole.h"
|
||||
#include "winreg.h"
|
||||
#define NO_SHLWAPI_STREAM
|
||||
#include <shlwapi.h>
|
||||
#include "shlwapi.h"
|
||||
|
||||
#include "rtf.h"
|
||||
|
||||
|
@ -238,91 +233,388 @@ ME_TextBuffer *ME_MakeText() {
|
|||
return buf;
|
||||
}
|
||||
|
||||
#define STREAMIN_BUFFER_SIZE 4096 /* M$ compatibility */
|
||||
|
||||
static LRESULT ME_StreamInText(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream, ME_Style *style)
|
||||
static LRESULT ME_StreamInText(ME_TextEditor *editor, DWORD dwFormat, ME_InStream *stream, ME_Style *style)
|
||||
{
|
||||
BYTE buffer[STREAMIN_BUFFER_SIZE+1];
|
||||
WCHAR wszText[STREAMIN_BUFFER_SIZE+1];
|
||||
WCHAR *pText;
|
||||
|
||||
TRACE("%08lx %p\n", dwFormat, stream);
|
||||
stream->dwError = 0;
|
||||
|
||||
do {
|
||||
long nDataSize = 0, nWideChars = 0;
|
||||
stream->dwError = stream->pfnCallback(stream->dwCookie,
|
||||
(dwFormat & SF_UNICODE ? (BYTE *)wszText : buffer),
|
||||
STREAMIN_BUFFER_SIZE, &nDataSize);
|
||||
|
||||
if (stream->dwError)
|
||||
break;
|
||||
if (!nDataSize)
|
||||
break;
|
||||
long nWideChars = 0;
|
||||
|
||||
if (!stream->dwSize)
|
||||
{
|
||||
ME_StreamInFill(stream);
|
||||
if (stream->editstream->dwError)
|
||||
break;
|
||||
if (!stream->dwSize)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(dwFormat & SF_UNICODE))
|
||||
{
|
||||
/* FIXME? this is doomed to fail on true MBCS like UTF-8, luckily they're unlikely to be used as CP_ACP */
|
||||
nWideChars = MultiByteToWideChar(CP_ACP, 0, buffer, nDataSize, wszText, STREAMIN_BUFFER_SIZE);
|
||||
nWideChars = MultiByteToWideChar(CP_ACP, 0, stream->buffer, stream->dwSize, wszText, STREAMIN_BUFFER_SIZE);
|
||||
pText = wszText;
|
||||
}
|
||||
else
|
||||
nWideChars = nDataSize>>1;
|
||||
ME_InsertTextFromCursor(editor, 0, wszText, nWideChars, style);
|
||||
if (nDataSize<STREAMIN_BUFFER_SIZE)
|
||||
{
|
||||
nWideChars = stream->dwSize >> 1;
|
||||
pText = (WCHAR *)stream->buffer;
|
||||
}
|
||||
|
||||
ME_InsertTextFromCursor(editor, 0, pText, nWideChars, style);
|
||||
if (stream->dwSize < STREAMIN_BUFFER_SIZE)
|
||||
break;
|
||||
} while(1);
|
||||
ME_CommitUndo(editor);
|
||||
ME_CommitUndo(editor);
|
||||
ME_Repaint(editor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ME_RTFCharAttrHook(RTF_Info *info)
|
||||
{
|
||||
CHARFORMAT2W fmt;
|
||||
fmt.cbSize = sizeof(fmt);
|
||||
fmt.dwMask = 0;
|
||||
|
||||
switch(info->rtfMinor)
|
||||
{
|
||||
case rtfPlain:
|
||||
/* FIXME add more flags once they're implemented */
|
||||
fmt.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR | CFM_BACKCOLOR | CFM_SIZE | CFM_WEIGHT;
|
||||
fmt.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR;
|
||||
fmt.yHeight = 12*20; /* 12pt */
|
||||
fmt.wWeight = 400;
|
||||
break;
|
||||
case rtfBold:
|
||||
fmt.dwMask = CFM_BOLD;
|
||||
fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
|
||||
break;
|
||||
case rtfItalic:
|
||||
fmt.dwMask = CFM_ITALIC;
|
||||
fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
|
||||
break;
|
||||
case rtfUnderline:
|
||||
fmt.dwMask = CFM_UNDERLINE;
|
||||
fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
|
||||
break;
|
||||
case rtfStrikeThru:
|
||||
fmt.dwMask = CFM_STRIKEOUT;
|
||||
fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
|
||||
break;
|
||||
case rtfBackColor:
|
||||
fmt.dwMask = CFM_BACKCOLOR;
|
||||
fmt.dwEffects = 0;
|
||||
if (info->rtfParam == 0)
|
||||
fmt.dwEffects = CFE_AUTOBACKCOLOR;
|
||||
else if (info->rtfParam != rtfNoParam)
|
||||
{
|
||||
RTFColor *c = RTFGetColor(info, info->rtfParam);
|
||||
fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed);
|
||||
}
|
||||
break;
|
||||
case rtfForeColor:
|
||||
fmt.dwMask = CFM_COLOR;
|
||||
fmt.dwEffects = 0;
|
||||
if (info->rtfParam == 0)
|
||||
fmt.dwEffects = CFE_AUTOCOLOR;
|
||||
else if (info->rtfParam != rtfNoParam)
|
||||
{
|
||||
RTFColor *c = RTFGetColor(info, info->rtfParam);
|
||||
fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed);
|
||||
}
|
||||
break;
|
||||
case rtfFontNum:
|
||||
if (info->rtfParam != rtfNoParam)
|
||||
{
|
||||
RTFFont *f = RTFGetFont(info, info->rtfParam);
|
||||
if (f)
|
||||
{
|
||||
MultiByteToWideChar(CP_ACP, 0, f->rtfFName, -1, fmt.szFaceName, sizeof(fmt.szFaceName)/sizeof(WCHAR));
|
||||
fmt.szFaceName[sizeof(fmt.szFaceName)/sizeof(WCHAR)-1] = '\0';
|
||||
fmt.bCharSet = f->rtfFCharSet;
|
||||
fmt.dwMask = CFM_FACE | CFM_CHARSET;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case rtfFontSize:
|
||||
fmt.dwMask = CFM_SIZE;
|
||||
if (info->rtfParam != rtfNoParam)
|
||||
fmt.yHeight = info->rtfParam*10;
|
||||
break;
|
||||
}
|
||||
if (fmt.dwMask) {
|
||||
ME_Style *style2;
|
||||
RTFFlushOutputBuffer(info);
|
||||
/* FIXME too slow ? how come ? */
|
||||
style2 = ME_ApplyStyle(info->style, &fmt);
|
||||
ME_ReleaseStyle(info->style);
|
||||
info->style = style2;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME this function doesn't get any information about context of the RTF tag, which is very bad,
|
||||
the same tags mean different things in different contexts */
|
||||
void ME_RTFParAttrHook(RTF_Info *info)
|
||||
{
|
||||
PARAFORMAT2 fmt;
|
||||
fmt.cbSize = sizeof(fmt);
|
||||
fmt.dwMask = 0;
|
||||
|
||||
switch(info->rtfMinor)
|
||||
{
|
||||
case rtfParDef: /* I'm not 100% sure what does it do, but I guess it restores default paragraph attributes */
|
||||
fmt.dwMask = PFM_ALIGNMENT | PFM_TABSTOPS | PFM_OFFSET | PFM_STARTINDENT;
|
||||
fmt.wAlignment = PFA_LEFT;
|
||||
fmt.cTabCount = 0;
|
||||
fmt.dxOffset = fmt.dxStartIndent = 0;
|
||||
break;
|
||||
case rtfFirstIndent:
|
||||
ME_GetSelectionParaFormat(info->editor, &fmt);
|
||||
fmt.dwMask = PFM_STARTINDENT;
|
||||
fmt.dxStartIndent = info->rtfParam + fmt.dxOffset;
|
||||
break;
|
||||
case rtfLeftIndent:
|
||||
{
|
||||
int first, left;
|
||||
ME_GetSelectionParaFormat(info->editor, &fmt);
|
||||
first = fmt.dxStartIndent;
|
||||
left = info->rtfParam;
|
||||
fmt.dwMask = PFM_STARTINDENT|PFM_OFFSET;
|
||||
fmt.dxStartIndent = first + left;
|
||||
fmt.dxOffset = -first;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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++;
|
||||
break;
|
||||
case rtfEndGroup:
|
||||
{
|
||||
ME_Style *s;
|
||||
RTFFlushOutputBuffer(info);
|
||||
info->stackTop--;
|
||||
/* 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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ME_StreamInFill(ME_InStream *stream)
|
||||
{
|
||||
stream->editstream->dwError = stream->editstream->pfnCallback(stream->editstream->dwCookie,
|
||||
stream->buffer,
|
||||
sizeof(stream->buffer),
|
||||
&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;
|
||||
ME_UndoItem *pUI;
|
||||
int nEventMask = editor->nEventMask;
|
||||
ME_InStream inStream;
|
||||
|
||||
TRACE("%p %p\n", stream, editor->hWnd);
|
||||
editor->nEventMask = 0;
|
||||
|
||||
ME_GetSelection(editor, &from, &to);
|
||||
if (format & SFF_SELECTION) {
|
||||
style = ME_GetSelectionInsertStyle(editor);
|
||||
SendMessageW(editor->hWnd, WM_CLEAR, 0, 0);
|
||||
|
||||
ME_InternalDeleteText(editor, from, to-from);
|
||||
}
|
||||
else {
|
||||
style = editor->pBuffer->pDefaultStyle;
|
||||
ME_AddRefStyle(style);
|
||||
SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
|
||||
SetWindowTextA(editor->hWnd, "");
|
||||
ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
|
||||
from = to = 0;
|
||||
ME_ClearTempStyle(editor);
|
||||
/* FIXME restore default paragraph formatting ! */
|
||||
}
|
||||
|
||||
nUndoMode = editor->nUndoMode;
|
||||
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, "{\\rtf1", 6) && strncmp(inStream.buffer, "{\\urtf", 6))
|
||||
{
|
||||
format &= ~SF_RTF;
|
||||
format |= SF_TEXT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (format & SF_RTF) {
|
||||
/* setup the RTF parser */
|
||||
memset(&parser, 0, sizeof parser);
|
||||
RTFSetEditStream(&parser, stream);
|
||||
parser.rtfFormat = format&(SF_TEXT|SF_RTF);
|
||||
parser.hwndEdit = editor->hWnd;
|
||||
WriterInit(&parser);
|
||||
RTFInit(&parser);
|
||||
BeginFile(&parser);
|
||||
|
||||
/* do the parsing */
|
||||
RTFRead(&parser);
|
||||
RTFFlushOutputBuffer(&parser);
|
||||
}
|
||||
else if (format & SF_TEXT)
|
||||
ME_StreamInText(editor, format, stream, style);
|
||||
else
|
||||
ERR("EM_STREAMIN without SF_TEXT or SF_RTF\n");
|
||||
/* put the cursor at the top */
|
||||
if (!(format & SFF_SELECTION))
|
||||
SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
|
||||
else
|
||||
if (!inStream.editstream->dwError)
|
||||
{
|
||||
/* FIXME where to put cursor now ? */
|
||||
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);
|
||||
else
|
||||
{
|
||||
/* FIXME where to put cursor now ? */
|
||||
}
|
||||
}
|
||||
ME_ReleaseStyle(style);
|
||||
|
||||
editor->nUndoMode = nUndoMode;
|
||||
pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL);
|
||||
TRACE("from %d to %d\n", from, to);
|
||||
if (pUI && from < to)
|
||||
{
|
||||
pUI->nStart = from;
|
||||
pUI->nLen = to-from;
|
||||
}
|
||||
ME_CommitUndo(editor);
|
||||
ME_ReleaseStyle(style);
|
||||
editor->nEventMask = nEventMask;
|
||||
InvalidateRect(editor->hWnd, NULL, TRUE);
|
||||
ME_UpdateRepaint(editor);
|
||||
if (!(format & SFF_SELECTION)) {
|
||||
ME_ClearTempStyle(editor);
|
||||
}
|
||||
ME_MoveCaret(editor);
|
||||
ME_SendSelChange(editor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
ME_TextEditor *ME_MakeEditor(HWND hWnd) {
|
||||
ME_TextEditor *ed = ALLOC_OBJ(ME_TextEditor);
|
||||
HDC hDC;
|
||||
|
@ -340,7 +632,6 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
|
|||
ed->pCursors[1].pRun = ME_FindItemFwd(ed->pBuffer->pFirst, diRun);
|
||||
ed->pCursors[1].nOffset = 0;
|
||||
ed->nLastTotalLength = ed->nTotalLength = 0;
|
||||
ed->nScrollPos = 0;
|
||||
ed->nUDArrowX = -1;
|
||||
ed->nSequence = 0;
|
||||
ed->rgbBackColor = -1;
|
||||
|
@ -351,6 +642,7 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
|
|||
ed->nUndoMode = umAddToUndo;
|
||||
ed->nParagraphs = 1;
|
||||
ed->nLastSelStart = ed->nLastSelEnd = 0;
|
||||
ed->nScrollPosY = 0;
|
||||
for (i=0; i<HFONT_CACHE_SIZE; i++)
|
||||
{
|
||||
ed->pFontCache[i].nRefs = 0;
|
||||
|
@ -361,6 +653,70 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
|
|||
return ed;
|
||||
}
|
||||
|
||||
typedef struct tagME_GlobalDestStruct
|
||||
{
|
||||
HGLOBAL hData;
|
||||
int nLength;
|
||||
} ME_GlobalDestStruct;
|
||||
|
||||
static DWORD CALLBACK ME_AppendToHGLOBAL(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb)
|
||||
{
|
||||
ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie;
|
||||
int nMaxSize;
|
||||
BYTE *pDest;
|
||||
|
||||
nMaxSize = GlobalSize(pData->hData);
|
||||
if (pData->nLength+cb+1 >= cb)
|
||||
{
|
||||
/* round up to 2^17 */
|
||||
int nNewSize = (((nMaxSize+cb+1)|0x1FFFF)+1) & 0xFFFE0000;
|
||||
pData->hData = GlobalReAlloc(pData->hData, nNewSize, 0);
|
||||
}
|
||||
pDest = (BYTE *)GlobalLock(pData->hData);
|
||||
memcpy(pDest + pData->nLength, lpBuff, cb);
|
||||
pData->nLength += cb;
|
||||
pDest[pData->nLength] = '\0';
|
||||
GlobalUnlock(pData->hData);
|
||||
*pcb = cb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DWORD CALLBACK ME_ReadFromHGLOBALUnicode(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb)
|
||||
{
|
||||
ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie;
|
||||
int i;
|
||||
WORD *pSrc, *pDest;
|
||||
|
||||
cb = cb >> 1;
|
||||
pDest = (WORD *)lpBuff;
|
||||
pSrc = (WORD *)GlobalLock(pData->hData);
|
||||
for (i = 0; i<cb && pSrc[pData->nLength+i]; i++) {
|
||||
pDest[i] = pSrc[pData->nLength+i];
|
||||
}
|
||||
pData->nLength += i;
|
||||
*pcb = 2*i;
|
||||
GlobalUnlock(pData->hData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DWORD CALLBACK ME_ReadFromHGLOBALRTF(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb)
|
||||
{
|
||||
ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie;
|
||||
int i;
|
||||
BYTE *pSrc, *pDest;
|
||||
|
||||
pDest = lpBuff;
|
||||
pSrc = (BYTE *)GlobalLock(pData->hData);
|
||||
for (i = 0; i<cb && pSrc[pData->nLength+i]; i++) {
|
||||
pDest[i] = pSrc[pData->nLength+i];
|
||||
}
|
||||
pData->nLength += i;
|
||||
*pcb = i;
|
||||
GlobalUnlock(pData->hData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ME_DestroyEditor(ME_TextEditor *editor)
|
||||
{
|
||||
ME_DisplayItem *pFirst = editor->pBuffer->pFirst;
|
||||
|
@ -401,7 +757,6 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
switch(msg) {
|
||||
|
||||
UNSUPPORTED_MSG(EM_AUTOURLDETECT)
|
||||
UNSUPPORTED_MSG(EM_CANPASTE)
|
||||
UNSUPPORTED_MSG(EM_CHARFROMPOS)
|
||||
UNSUPPORTED_MSG(EM_DISPLAYBAND)
|
||||
UNSUPPORTED_MSG(EM_EXLIMITTEXT)
|
||||
|
@ -448,9 +803,7 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
UNSUPPORTED_MSG(EM_SETUNDOLIMIT)
|
||||
UNSUPPORTED_MSG(EM_SETWORDBREAKPROC)
|
||||
UNSUPPORTED_MSG(EM_SETWORDBREAKPROCEX)
|
||||
UNSUPPORTED_MSG(EM_STREAMOUT)
|
||||
UNSUPPORTED_MSG(WM_SETFONT)
|
||||
UNSUPPORTED_MSG(WM_PASTE)
|
||||
UNSUPPORTED_MSG(WM_STYLECHANGING)
|
||||
UNSUPPORTED_MSG(WM_STYLECHANGED)
|
||||
/* UNSUPPORTED_MSG(WM_UNICHAR) FIXME missing in Wine headers */
|
||||
|
@ -459,6 +812,8 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
|
||||
case EM_STREAMIN:
|
||||
return ME_StreamIn(editor, wParam, (EDITSTREAM*)lParam);
|
||||
case EM_STREAMOUT:
|
||||
return ME_StreamOut(editor, wParam, (EDITSTREAM *)lParam);
|
||||
case WM_GETDLGCODE:
|
||||
{
|
||||
UINT code = DLGC_WANTCHARS|DLGC_WANTARROWS;
|
||||
|
@ -557,6 +912,7 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
case EM_SETCHARFORMAT:
|
||||
{
|
||||
CHARFORMAT2W buf, *p;
|
||||
BOOL bRepaint = TRUE;
|
||||
p = ME_ToCF2W(&buf, (CHARFORMAT2W *)lParam);
|
||||
if (!wParam)
|
||||
ME_SetDefaultCharFormat(editor, p);
|
||||
|
@ -564,10 +920,15 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
FIXME("word selection not supported\n");
|
||||
else if (wParam == SCF_ALL)
|
||||
ME_SetCharFormat(editor, 0, ME_GetTextLength(editor), p);
|
||||
else
|
||||
else {
|
||||
int from, to;
|
||||
ME_GetSelection(editor, &from, &to);
|
||||
bRepaint = (from != to);
|
||||
ME_SetSelectionCharFormat(editor, p);
|
||||
}
|
||||
ME_CommitUndo(editor);
|
||||
ME_UpdateRepaint(editor);
|
||||
if (bRepaint)
|
||||
ME_UpdateRepaint(editor);
|
||||
return 0;
|
||||
}
|
||||
case EM_GETCHARFORMAT:
|
||||
|
@ -583,6 +944,7 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
}
|
||||
case EM_SETPARAFORMAT:
|
||||
ME_SetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam);
|
||||
ME_UpdateRepaint(editor);
|
||||
ME_CommitUndo(editor);
|
||||
return 0;
|
||||
case EM_GETPARAFORMAT:
|
||||
|
@ -635,12 +997,49 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
ME_UpdateRepaint(editor);
|
||||
return 0;
|
||||
}
|
||||
case EM_CANPASTE:
|
||||
{
|
||||
UINT nRTFFormat = RegisterClipboardFormatA("Rich Text Format");
|
||||
if (IsClipboardFormatAvailable(nRTFFormat))
|
||||
return TRUE;
|
||||
if (IsClipboardFormatAvailable(CF_UNICODETEXT))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
case WM_PASTE:
|
||||
{
|
||||
DWORD dwFormat = 0;
|
||||
EDITSTREAM es;
|
||||
ME_GlobalDestStruct gds;
|
||||
UINT nRTFFormat = RegisterClipboardFormatA("Rich Text Format");
|
||||
UINT cf = 0;
|
||||
|
||||
if (IsClipboardFormatAvailable(nRTFFormat))
|
||||
cf = nRTFFormat, dwFormat = SF_RTF;
|
||||
else if (IsClipboardFormatAvailable(CF_UNICODETEXT))
|
||||
cf = CF_UNICODETEXT, dwFormat = SF_TEXT|SF_UNICODE;
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (!OpenClipboard(hWnd))
|
||||
return 0;
|
||||
gds.hData = GetClipboardData(cf);
|
||||
gds.nLength = 0;
|
||||
es.dwCookie = (DWORD)&gds;
|
||||
es.pfnCallback = dwFormat == SF_RTF ? ME_ReadFromHGLOBALRTF : ME_ReadFromHGLOBALUnicode;
|
||||
SendMessageW(hWnd, EM_STREAMIN, dwFormat|SFF_SELECTION, (LPARAM)&es);
|
||||
|
||||
CloseClipboard();
|
||||
return 0;
|
||||
}
|
||||
case WM_CUT:
|
||||
case WM_COPY:
|
||||
{
|
||||
int from, to, pars;
|
||||
WCHAR *data;
|
||||
HANDLE hData;
|
||||
EDITSTREAM es;
|
||||
ME_GlobalDestStruct gds;
|
||||
|
||||
if (!OpenClipboard(hWnd))
|
||||
return 0;
|
||||
|
@ -652,7 +1051,17 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
data = (WCHAR *)GlobalLock(hData);
|
||||
ME_GetTextW(editor, data, from, to-from, TRUE);
|
||||
GlobalUnlock(hData);
|
||||
SetClipboardData(CF_UNICODETEXT, hData);
|
||||
|
||||
gds.hData = GlobalAlloc(GMEM_MOVEABLE, 0);
|
||||
gds.nLength = 0;
|
||||
es.dwCookie = (DWORD)&gds;
|
||||
es.pfnCallback = ME_AppendToHGLOBAL;
|
||||
SendMessageW(hWnd, EM_STREAMOUT, SFF_SELECTION|SF_RTF, (LPARAM)&es);
|
||||
GlobalReAlloc(gds.hData, gds.nLength+1, 0);
|
||||
|
||||
SetClipboardData(CF_UNICODETEXT, hData);
|
||||
SetClipboardData(RegisterClipboardFormatA("Rich Text Format"), gds.hData);
|
||||
|
||||
CloseClipboard();
|
||||
if (msg == WM_CUT)
|
||||
{
|
||||
|
@ -785,7 +1194,7 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
return 0; /* FIXME really 0 ? */
|
||||
}
|
||||
wstr = LOWORD(wParam);
|
||||
if (((unsigned)wstr)>=' ' || wstr=='\r') {
|
||||
if (((unsigned)wstr)>=' ' || wstr=='\r' || wstr=='\t') {
|
||||
/* FIXME maybe it would make sense to call EM_REPLACESEL instead ? */
|
||||
ME_Style *style = ME_GetInsertStyle(editor, 0);
|
||||
ME_SaveTempStyle(editor);
|
||||
|
@ -798,22 +1207,69 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
}
|
||||
case WM_VSCROLL:
|
||||
{
|
||||
int nPos = editor->nScrollPosY;
|
||||
si.cbSize = sizeof(SCROLLINFO);
|
||||
si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE|SIF_TRACKPOS;
|
||||
GetScrollInfo(hWnd, SB_VERT, &si);
|
||||
switch(LOWORD(wParam)) {
|
||||
case SB_THUMBTRACK:
|
||||
SetScrollPos(hWnd, SB_VERT, si.nTrackPos, FALSE);
|
||||
ScrollWindow(hWnd, 0, si.nPos-si.nTrackPos, NULL, NULL);
|
||||
/* InvalidateRect(hWnd, NULL, TRUE); */
|
||||
UpdateWindow(hWnd);
|
||||
case SB_LINEUP:
|
||||
nPos -= 24; /* FIXME follow the original */
|
||||
if (nPos<0) nPos = 0;
|
||||
break;
|
||||
case SB_LINEDOWN:
|
||||
{
|
||||
int nEnd = editor->nTotalLength - editor->sizeWindow.cy;
|
||||
nPos += 24; /* FIXME follow the original */
|
||||
if (nPos>=nEnd) nPos = nEnd;
|
||||
break;
|
||||
}
|
||||
case SB_PAGEUP:
|
||||
nPos -= editor->sizeWindow.cy;
|
||||
if (nPos<0) nPos = 0;
|
||||
break;
|
||||
case SB_PAGEDOWN:
|
||||
nPos += editor->sizeWindow.cy;
|
||||
if (nPos>=editor->nTotalLength) nPos = editor->nTotalLength-1;
|
||||
break;
|
||||
case SB_THUMBTRACK:
|
||||
case SB_THUMBPOSITION:
|
||||
nPos = si.nTrackPos;
|
||||
break;
|
||||
}
|
||||
if (nPos != editor->nScrollPosY) {
|
||||
ScrollWindow(hWnd, 0, editor->nScrollPosY-nPos, NULL, NULL);
|
||||
editor->nScrollPosY = nPos;
|
||||
SetScrollPos(hWnd, SB_VERT, nPos, TRUE);
|
||||
UpdateWindow(hWnd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_MOUSEWHEEL:
|
||||
{
|
||||
int gcWheelDelta = 0, nPos = editor->nScrollPosY;
|
||||
UINT pulScrollLines;
|
||||
|
||||
SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
|
||||
gcWheelDelta -= GET_WHEEL_DELTA_WPARAM(wParam);
|
||||
if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
|
||||
nPos += pulScrollLines * (gcWheelDelta / WHEEL_DELTA) * 8;
|
||||
if(nPos>=editor->nTotalLength)
|
||||
nPos = editor->nTotalLength - 1;
|
||||
if (nPos<0)
|
||||
nPos = 0;
|
||||
if (nPos != editor->nScrollPosY) {
|
||||
ScrollWindow(hWnd, 0, editor->nScrollPosY-nPos, NULL, NULL);
|
||||
editor->nScrollPosY = nPos;
|
||||
SetScrollPos(hWnd, SB_VERT, nPos, TRUE);
|
||||
UpdateWindow(hWnd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_SIZE:
|
||||
{
|
||||
ME_MarkAllForWrapping(editor);
|
||||
ME_WrapMarkedParagraphs(editor);
|
||||
ME_UpdateScrollBar(editor);
|
||||
ME_Repaint(editor);
|
||||
return DefWindowProcW(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
|
@ -861,26 +1317,18 @@ int ME_CountParagraphsBetween(ME_TextEditor *editor, int from, int to)
|
|||
return i;
|
||||
}
|
||||
|
||||
|
||||
int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, int bCRLF)
|
||||
{
|
||||
ME_DisplayItem *item = ME_FindItemFwd(editor->pBuffer->pFirst, diParagraph);
|
||||
ME_DisplayItem *item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart);
|
||||
int nWritten = 0;
|
||||
|
||||
while(item && item->member.para.next_para->member.para.nCharOfs <= nStart)
|
||||
item = ME_FindItemFwd(item, diParagraph);
|
||||
if (!item) {
|
||||
*buffer = L'\0';
|
||||
return 0;
|
||||
}
|
||||
nStart -= item->member.para.nCharOfs;
|
||||
|
||||
do {
|
||||
item = ME_FindItemFwd(item, diRun);
|
||||
} while(item && (item->member.run.nCharOfs + ME_StrLen(item->member.run.strText) <= nStart));
|
||||
assert(item);
|
||||
|
||||
nStart -= item->member.run.nCharOfs;
|
||||
|
||||
if (nStart)
|
||||
{
|
||||
int nLen = ME_StrLen(item->member.run.strText) - nStart;
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
|
||||
#include "editstr.h"
|
||||
|
||||
#define ALLOC_OBJ(type) (type *)HeapAlloc(me_heap, 0, sizeof(type))
|
||||
#define ALLOC_N_OBJ(type, count) (type *)HeapAlloc(me_heap, 0, count*sizeof(type))
|
||||
#define ALLOC_OBJ(type) HeapAlloc(me_heap, 0, sizeof(type))
|
||||
#define ALLOC_N_OBJ(type, count) HeapAlloc(me_heap, 0, (count)*sizeof(type))
|
||||
#define FREE_OBJ(ptr) HeapFree(me_heap, 0, ptr)
|
||||
|
||||
/* style.c */
|
||||
|
@ -85,6 +85,10 @@ void ME_EndToUnicode(HWND hWnd, LPVOID psz);
|
|||
LPSTR ME_ToAnsi(HWND hWnd, LPVOID psz);
|
||||
void ME_EndToAnsi(HWND hWnd, LPVOID psz);
|
||||
|
||||
static inline int ME_IsWSpace(WCHAR ch)
|
||||
{
|
||||
return ch > '\0' && ch <= ' ';
|
||||
}
|
||||
|
||||
/* note: those two really return the first matching offset (starting from EOS)+1
|
||||
* in other words, an offset of the first trailing white/black */
|
||||
|
@ -104,7 +108,7 @@ ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem
|
|||
void ME_CheckCharOffsets(ME_TextEditor *editor);
|
||||
void ME_PropagateCharOffset(ME_DisplayItem *p, int shift);
|
||||
void ME_GetGraphicsSize(ME_TextEditor *editor, ME_Run *run, SIZE *pSize);
|
||||
int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run);
|
||||
int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Paragraph *para, ME_Run *run);
|
||||
/* this one accounts for 1/2 char tolerance */
|
||||
int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run);
|
||||
int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset);
|
||||
|
@ -116,8 +120,8 @@ ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, i
|
|||
int ME_FindSplitPoint(ME_Context *c, POINT *pt, ME_Run *run, int desperate);
|
||||
void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run);
|
||||
ME_DisplayItem *ME_SplitFurther(ME_TextEditor *editor, ME_DisplayItem *run);
|
||||
void ME_CalcRunExtent(ME_Context *c, ME_Run *run);
|
||||
SIZE ME_GetRunSize(ME_Context *c, ME_Run *run, int nLen);
|
||||
void ME_CalcRunExtent(ME_Context *c, ME_Paragraph *para, ME_Run *run);
|
||||
SIZE ME_GetRunSize(ME_Context *c, ME_Paragraph *para, ME_Run *run, int nLen);
|
||||
void ME_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCursor);
|
||||
void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **ppRun, int *pOfs);
|
||||
int ME_CharOfsFromRunOfs(ME_TextEditor *editor, ME_DisplayItem *pRun, int nOfs);
|
||||
|
@ -157,13 +161,14 @@ void ME_InsertGraphicsFromCursor(ME_TextEditor *editor, int nCursor);
|
|||
void ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars);
|
||||
int ME_GetTextLength(ME_TextEditor *editor);
|
||||
ME_Style *ME_GetSelectionInsertStyle(ME_TextEditor *editor);
|
||||
BOOL ME_UpdateSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor);
|
||||
|
||||
/* wrap.c */
|
||||
void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp);
|
||||
ME_DisplayItem *ME_MakeRow(int height, int baseline, int width);
|
||||
void ME_InsertRowStart(ME_WrapContext *wc, ME_DisplayItem *pEnd);
|
||||
void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp);
|
||||
void ME_WrapMarkedParagraphs(ME_TextEditor *editor);
|
||||
BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor);
|
||||
|
||||
/* para.c */
|
||||
ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *run);
|
||||
|
@ -185,10 +190,11 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpda
|
|||
void ME_Repaint(ME_TextEditor *editor);
|
||||
void ME_UpdateRepaint(ME_TextEditor *editor);
|
||||
void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph);
|
||||
void ME_UpdateScrollBar(ME_TextEditor *editor, int ypos);
|
||||
int ME_GetScrollPos(ME_TextEditor *editor);
|
||||
void ME_UpdateScrollBar(ME_TextEditor *editor);
|
||||
int ME_GetYScrollPos(ME_TextEditor *editor);
|
||||
void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun);
|
||||
COLORREF ME_GetBackColor(ME_TextEditor *editor);
|
||||
void ME_Scroll(ME_TextEditor *editor, int cx, int cy);
|
||||
|
||||
/* richole.c */
|
||||
extern LRESULT CreateIRichEditOle(LPVOID *);
|
||||
|
@ -206,7 +212,12 @@ void ME_Undo(ME_TextEditor *editor);
|
|||
void ME_Redo(ME_TextEditor *editor);
|
||||
void ME_EmptyUndoStack(ME_TextEditor *editor);
|
||||
int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, BOOL bCRLF);
|
||||
ME_DisplayItem *ME_FindItemAtOffset(ME_TextEditor *editor, ME_DIType nItemType, int nOffset, int *nItemOffset);
|
||||
void ME_StreamInFill(ME_InStream *stream);
|
||||
|
||||
extern int me_debug;
|
||||
extern HANDLE me_heap;
|
||||
extern void DoWrap(ME_TextEditor *editor);
|
||||
|
||||
/* writer.c */
|
||||
LRESULT ME_StreamOut(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream);
|
||||
|
|
|
@ -86,6 +86,8 @@ typedef enum {
|
|||
#define MERF_STYLEFLAGS 0x0FFF
|
||||
/* run contains non-text content, which has its own rules for wrapping, sizing etc */
|
||||
#define MERF_GRAPHICS 1
|
||||
/* run is a tab (or, in future, any kind of content whose size is dependent on run position) */
|
||||
#define MERF_TAB 2
|
||||
|
||||
/* run is splittable (contains white spaces in the middle or end) */
|
||||
#define MERF_SPLITTABLE 0x001000
|
||||
|
@ -102,6 +104,11 @@ typedef enum {
|
|||
/* the "end of paragraph" run, contains 1 character */
|
||||
#define MERF_ENDPARA 0x100000
|
||||
|
||||
/* runs with any of these flags set cannot be joined */
|
||||
#define MERF_NOJOIN (MERF_GRAPHICS|MERF_TAB|MERF_ENDPARA)
|
||||
/* runs that don't contain real text */
|
||||
#define MERF_NOTEXT (MERF_GRAPHICS|MERF_TAB|MERF_ENDPARA)
|
||||
|
||||
/* those flags are kept when the row is split */
|
||||
#define MERF_SPLITMASK (~(0))
|
||||
|
||||
|
@ -192,6 +199,40 @@ typedef enum {
|
|||
umAddBackToUndo
|
||||
} ME_UndoMode;
|
||||
|
||||
typedef struct tagME_FontTableItem {
|
||||
BYTE bCharSet;
|
||||
WCHAR *szFaceName;
|
||||
} ME_FontTableItem;
|
||||
|
||||
|
||||
#define STREAMIN_BUFFER_SIZE 4096 /* M$ compatibility */
|
||||
|
||||
struct tagME_InStream {
|
||||
EDITSTREAM *editstream;
|
||||
DWORD dwSize;
|
||||
DWORD dwUsed;
|
||||
BYTE buffer[STREAMIN_BUFFER_SIZE];
|
||||
};
|
||||
typedef struct tagME_InStream ME_InStream;
|
||||
|
||||
|
||||
#define STREAMOUT_BUFFER_SIZE 4096
|
||||
#define STREAMOUT_FONTTBL_SIZE 8192
|
||||
#define STREAMOUT_COLORTBL_SIZE 1024
|
||||
|
||||
typedef struct tagME_OutStream {
|
||||
EDITSTREAM *stream;
|
||||
char buffer[STREAMOUT_BUFFER_SIZE];
|
||||
UINT pos, written;
|
||||
UINT nCodePage;
|
||||
UINT nFontTblLen;
|
||||
ME_FontTableItem fonttbl[STREAMOUT_FONTTBL_SIZE];
|
||||
UINT nColorTblLen;
|
||||
COLORREF colortbl[STREAMOUT_COLORTBL_SIZE];
|
||||
UINT nDefaultFont;
|
||||
UINT nDefaultCodePage;
|
||||
} ME_OutStream;
|
||||
|
||||
typedef struct tagME_FontCacheItem
|
||||
{
|
||||
LOGFONTW lfSpecs;
|
||||
|
@ -210,7 +251,6 @@ typedef struct tagME_TextEditor
|
|||
ME_Cursor *pCursors;
|
||||
int nCursors;
|
||||
SIZE sizeWindow;
|
||||
int nScrollPos;
|
||||
int nTotalLength, nLastTotalLength;
|
||||
int nUDArrowX;
|
||||
int nSequence;
|
||||
|
@ -224,6 +264,9 @@ typedef struct tagME_TextEditor
|
|||
int nParagraphs;
|
||||
int nLastSelStart, nLastSelEnd;
|
||||
ME_FontCacheItem pFontCache[HFONT_CACHE_SIZE];
|
||||
ME_OutStream *pStream;
|
||||
BOOL bScrollX, bScrollY;
|
||||
int nScrollPosY;
|
||||
} ME_TextEditor;
|
||||
|
||||
typedef struct tagME_Context
|
||||
|
|
|
@ -28,14 +28,16 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpda
|
|||
int yoffset;
|
||||
|
||||
editor->nSequence++;
|
||||
yoffset = GetScrollPos(editor->hWnd, SB_VERT);
|
||||
yoffset = ME_GetYScrollPos(editor);
|
||||
ME_InitContext(&c, editor, hDC);
|
||||
SetBkMode(hDC, TRANSPARENT);
|
||||
ME_MoveCaret(editor);
|
||||
item = editor->pBuffer->pFirst->next;
|
||||
c.pt.y -= yoffset;
|
||||
while(item != editor->pBuffer->pLast) {
|
||||
int ye;
|
||||
assert(item->type == diParagraph);
|
||||
ye = c.pt.y + item->member.para.nHeight;
|
||||
if (!bOnlyNew || (item->member.para.nFlags & MEPF_REPAINT))
|
||||
{
|
||||
BOOL bPaint = (rcUpdate == NULL);
|
||||
|
@ -45,10 +47,11 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpda
|
|||
if (bPaint)
|
||||
{
|
||||
ME_DrawParagraph(&c, item);
|
||||
item->member.para.nFlags &= ~MEPF_REPAINT;
|
||||
if (!rcUpdate || (rcUpdate->top<=c.pt.y && rcUpdate->bottom>=ye))
|
||||
item->member.para.nFlags &= ~MEPF_REPAINT;
|
||||
}
|
||||
}
|
||||
c.pt.y += item->member.para.nHeight;
|
||||
c.pt.y = ye;
|
||||
item = item->member.para.next_para;
|
||||
}
|
||||
if (c.pt.y<c.rcView.bottom) {
|
||||
|
@ -146,18 +149,21 @@ void ME_Repaint(ME_TextEditor *editor)
|
|||
ME_DisplayItem *pRun = NULL;
|
||||
int nOffset = -1;
|
||||
HDC hDC;
|
||||
|
||||
int nCharOfs = ME_CharOfsFromRunOfs(editor, pCursor->pRun, pCursor->nOffset);
|
||||
|
||||
ME_RunOfsFromCharOfs(editor, nCharOfs, &pRun, &nOffset);
|
||||
assert(pRun == pCursor->pRun);
|
||||
assert(nOffset == pCursor->nOffset);
|
||||
ME_MarkSelectionForRepaint(editor);
|
||||
ME_WrapMarkedParagraphs(editor);
|
||||
if (ME_WrapMarkedParagraphs(editor)) {
|
||||
ME_UpdateScrollBar(editor);
|
||||
}
|
||||
hDC = GetDC(editor->hWnd);
|
||||
ME_HideCaret(editor);
|
||||
ME_PaintContent(editor, hDC, TRUE, NULL);
|
||||
ReleaseDC(editor->hWnd, hDC);
|
||||
ME_ShowCaret(editor);
|
||||
ME_EnsureVisible(editor, pCursor->pRun);
|
||||
}
|
||||
|
||||
void ME_UpdateRepaint(ME_TextEditor *editor)
|
||||
|
@ -244,6 +250,9 @@ void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Paragraph
|
|||
ME_Run *run = &rundi->member.run;
|
||||
int runofs = run->nCharOfs+para->nCharOfs;
|
||||
|
||||
/* you can always comment it out if you need visible paragraph marks */
|
||||
if (run->nFlags & (MERF_ENDPARA|MERF_TAB))
|
||||
return;
|
||||
if (run->nFlags & MERF_GRAPHICS) {
|
||||
int blfrom, blto;
|
||||
ME_GetSelection(c->editor, &blfrom, &blto);
|
||||
|
@ -302,19 +311,19 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
|
|||
visible = RectVisible(c->hDC, &rcPara);
|
||||
if (visible) {
|
||||
HBRUSH hbr;
|
||||
hbr = CreateSolidBrush(ME_GetBackColor(c->editor));
|
||||
/* left margin */
|
||||
rc.left = c->rcView.left;
|
||||
rc.right = c->rcView.left+nMargWidth;
|
||||
rc.top = y;
|
||||
rc.bottom = y+p->member.row.nHeight;
|
||||
FillRect(c->hDC, &rc, c->hbrMargin);
|
||||
FillRect(c->hDC, &rc, hbr/* c->hbrMargin */);
|
||||
/* right margin */
|
||||
rc.left = xe;
|
||||
rc.right = c->rcView.right;
|
||||
FillRect(c->hDC, &rc, c->hbrMargin);
|
||||
rc.left = c->rcView.left+para->nLeftMargin;
|
||||
FillRect(c->hDC, &rc, hbr/* c->hbrMargin */);
|
||||
rc.left = c->rcView.left+nMargWidth;
|
||||
rc.right = xe;
|
||||
hbr = CreateSolidBrush(ME_GetBackColor(c->editor));
|
||||
FillRect(c->hDC, &rc, hbr);
|
||||
DeleteObject(hbr);
|
||||
}
|
||||
|
@ -369,62 +378,103 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
|
|||
SetTextAlign(c->hDC, align);
|
||||
}
|
||||
|
||||
void ME_UpdateScrollBar(ME_TextEditor *editor, int ypos)
|
||||
void ME_Scroll(ME_TextEditor *editor, int cx, int cy)
|
||||
{
|
||||
float perc = 0.0;
|
||||
SCROLLINFO si;
|
||||
HWND hWnd = editor->hWnd;
|
||||
int overflow = editor->nTotalLength - editor->sizeWindow.cy;
|
||||
si.cbSize = sizeof(SCROLLINFO);
|
||||
si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE|SIF_TRACKPOS;
|
||||
GetScrollInfo(hWnd, SB_VERT, &si);
|
||||
|
||||
if (ypos < 0) {
|
||||
if (si.nMax<1) si.nMax = 1;
|
||||
perc = 1.0*si.nPos/si.nMax;
|
||||
ypos = perc*overflow;
|
||||
}
|
||||
if (ypos >= overflow && overflow > 0)
|
||||
ypos = overflow - 1;
|
||||
|
||||
if (overflow > 0) {
|
||||
EnableScrollBar(hWnd, SB_VERT, ESB_ENABLE_BOTH);
|
||||
SetScrollRange(hWnd, SB_VERT, 0, overflow, FALSE);
|
||||
SetScrollPos(hWnd, SB_VERT, ypos, TRUE);
|
||||
} else {
|
||||
EnableScrollBar(hWnd, SB_VERT, ESB_DISABLE_BOTH);
|
||||
SetScrollRange(hWnd, SB_VERT, 0, 0, FALSE);
|
||||
SetScrollPos(hWnd, SB_VERT, 0, TRUE);
|
||||
}
|
||||
if (ypos != si.nPos)
|
||||
si.cbSize = sizeof(SCROLLINFO);
|
||||
si.fMask = SIF_POS;
|
||||
GetScrollInfo(hWnd, SB_VERT, &si);
|
||||
si.nPos = editor->nScrollPosY -= cy;
|
||||
SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
|
||||
if (abs(cy) > editor->sizeWindow.cy)
|
||||
InvalidateRect(editor->hWnd, NULL, TRUE);
|
||||
else
|
||||
ScrollWindowEx(hWnd, cx, cy, NULL, NULL, NULL, NULL, SW_ERASE|SW_INVALIDATE);
|
||||
}
|
||||
|
||||
void ME_UpdateScrollBar(ME_TextEditor *editor)
|
||||
{
|
||||
HWND hWnd = editor->hWnd;
|
||||
SCROLLINFO si;
|
||||
int nOldLen = editor->nTotalLength;
|
||||
BOOL bScrollY = (editor->nTotalLength > editor->sizeWindow.cy);
|
||||
BOOL bUpdateScrollBars;
|
||||
si.cbSize = sizeof(si);
|
||||
si.fMask = SIF_POS | SIF_RANGE;
|
||||
GetScrollInfo(hWnd, SB_VERT, &si);
|
||||
bUpdateScrollBars = (bScrollY || editor->bScrollY)&& ((si.nMax != nOldLen) || (si.nPage != editor->sizeWindow.cy));
|
||||
|
||||
if (bScrollY != editor->bScrollY)
|
||||
{
|
||||
TRACE("ScrollWindow(%d, %d, %d, %0.4f)\n", si.nPos, si.nMax, ypos, perc);
|
||||
ScrollWindow(hWnd, 0, si.nPos - ypos, NULL, NULL);
|
||||
UpdateWindow(hWnd);
|
||||
si.fMask = SIF_RANGE | SIF_PAGE;
|
||||
si.nMin = 0;
|
||||
si.nPage = editor->sizeWindow.cy;
|
||||
if (bScrollY) {
|
||||
si.nMax = editor->nTotalLength;
|
||||
} else {
|
||||
si.nMax = 0;
|
||||
}
|
||||
SetScrollInfo(hWnd, SB_VERT, &si, FALSE);
|
||||
ME_MarkAllForWrapping(editor);
|
||||
editor->bScrollY = bScrollY;
|
||||
ME_WrapMarkedParagraphs(editor);
|
||||
bUpdateScrollBars = TRUE;
|
||||
}
|
||||
if (bUpdateScrollBars) {
|
||||
int nScroll = 0;
|
||||
si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
|
||||
if (editor->nTotalLength > editor->sizeWindow.cy) {
|
||||
si.nMax = editor->nTotalLength;
|
||||
si.nPage = editor->sizeWindow.cy;
|
||||
if (si.nPos > si.nMax-si.nPage) {
|
||||
nScroll = (si.nMax-si.nPage)-si.nPos;
|
||||
si.nPos = si.nMax-si.nPage;
|
||||
}
|
||||
}
|
||||
else {
|
||||
si.nMax = 0;
|
||||
si.nPage = 0;
|
||||
si.nPos = 0;
|
||||
}
|
||||
TRACE("min=%d max=%d page=%d pos=%d shift=%d\n", si.nMin, si.nMax, si.nPage, si.nPos, nScroll);
|
||||
editor->nScrollPosY = si.nPos;
|
||||
SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
|
||||
if (nScroll)
|
||||
ScrollWindow(hWnd, 0, -nScroll, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
int ME_GetScrollPos(ME_TextEditor *editor)
|
||||
int ME_GetYScrollPos(ME_TextEditor *editor)
|
||||
{
|
||||
return GetScrollPos(editor->hWnd, SB_VERT);
|
||||
return editor->nScrollPosY;
|
||||
}
|
||||
|
||||
void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun)
|
||||
{
|
||||
ME_DisplayItem *pRow = ME_FindItemBack(pRun, diStartRow);
|
||||
ME_DisplayItem *pPara = ME_FindItemBack(pRun, diParagraph);
|
||||
int y, yrel, yheight;
|
||||
int y, yrel, yheight, yold;
|
||||
HWND hWnd = editor->hWnd;
|
||||
|
||||
assert(pRow);
|
||||
assert(pPara);
|
||||
|
||||
y = pPara->member.para.nYPos+pRow->member.row.nYPos;
|
||||
yheight = pRow->member.row.nHeight;
|
||||
yrel = y - ME_GetScrollPos(editor);
|
||||
if (yrel < 0)
|
||||
ME_UpdateScrollBar(editor, y);
|
||||
else if (yrel + yheight > editor->sizeWindow.cy)
|
||||
{
|
||||
ME_UpdateScrollBar(editor, y + yheight - editor->sizeWindow.cy);
|
||||
yold = ME_GetYScrollPos(editor);
|
||||
yrel = y - yold;
|
||||
if (yrel < 0) {
|
||||
editor->nScrollPosY = y;
|
||||
SetScrollPos(hWnd, SB_VERT, y, TRUE);
|
||||
ScrollWindow(hWnd, 0, -yrel, NULL, NULL);
|
||||
UpdateWindow(hWnd);
|
||||
} else if (yrel + yheight > editor->sizeWindow.cy) {
|
||||
int newy = y+yheight-editor->sizeWindow.cy;
|
||||
editor->nScrollPosY = newy;
|
||||
SetScrollPos(hWnd, SB_VERT, newy, TRUE);
|
||||
ScrollWindow(hWnd, 0, -(newy-yold), NULL, NULL);
|
||||
UpdateWindow(hWnd);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ void ME_MakeFirstParagraph(HDC hDC, ME_TextBuffer *text)
|
|||
|
||||
ZeroMemory(&fmt, sizeof(fmt));
|
||||
fmt.cbSize = sizeof(fmt);
|
||||
fmt.dwMask = PFM_ALIGNMENT | PFM_OFFSET | PFM_STARTINDENT | PFM_RIGHTINDENT;
|
||||
fmt.dwMask = PFM_ALIGNMENT | PFM_OFFSET | PFM_STARTINDENT | PFM_RIGHTINDENT | PFM_TABSTOPS;
|
||||
|
||||
CopyMemory(para->member.para.pFmt, &fmt, sizeof(PARAFORMAT2));
|
||||
|
||||
|
@ -282,6 +282,18 @@ void ME_SetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *
|
|||
|
||||
if (pFmt->dwMask & PFM_ALIGNMENT)
|
||||
para->member.para.pFmt->wAlignment = pFmt->wAlignment;
|
||||
if (pFmt->dwMask & PFM_STARTINDENT)
|
||||
para->member.para.pFmt->dxStartIndent = pFmt->dxStartIndent;
|
||||
if (pFmt->dwMask & PFM_OFFSET)
|
||||
para->member.para.pFmt->dxOffset = pFmt->dxOffset;
|
||||
if (pFmt->dwMask & PFM_OFFSETINDENT)
|
||||
para->member.para.pFmt->dxStartIndent += pFmt->dxStartIndent;
|
||||
|
||||
if (pFmt->dwMask & PFM_TABSTOPS)
|
||||
{
|
||||
para->member.para.pFmt->cTabCount = pFmt->cTabCount;
|
||||
memcpy(para->member.para.pFmt->rgxTabs, pFmt->rgxTabs, pFmt->cTabCount*sizeof(int));
|
||||
}
|
||||
|
||||
/* FIXME to be continued (indents, bulleting and such) */
|
||||
|
||||
|
@ -310,7 +322,6 @@ void ME_SetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt)
|
|||
break;
|
||||
para = para->member.para.next_para;
|
||||
} while(1);
|
||||
ME_Repaint(editor);
|
||||
}
|
||||
|
||||
void ME_GetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *pFmt)
|
||||
|
@ -346,11 +357,28 @@ void ME_GetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt)
|
|||
ZeroMemory(&tmp, sizeof(tmp));
|
||||
tmp.cbSize = sizeof(tmp);
|
||||
ME_GetParaFormat(editor, para, &tmp);
|
||||
assert(tmp.dwMask & PFM_ALIGNMENT);
|
||||
|
||||
assert(tmp.dwMask & PFM_ALIGNMENT);
|
||||
if (pFmt->wAlignment != tmp.wAlignment)
|
||||
pFmt->dwMask &= ~PFM_ALIGNMENT;
|
||||
|
||||
assert(tmp.dwMask & PFM_STARTINDENT);
|
||||
if (pFmt->dxStartIndent != tmp.dxStartIndent)
|
||||
pFmt->dwMask &= ~PFM_STARTINDENT;
|
||||
|
||||
assert(tmp.dwMask & PFM_OFFSET);
|
||||
if (pFmt->dxOffset != tmp.dxOffset)
|
||||
pFmt->dwMask &= ~PFM_OFFSET;
|
||||
|
||||
assert(tmp.dwMask & PFM_TABSTOPS);
|
||||
if (pFmt->dwMask & PFM_TABSTOPS) {
|
||||
if (pFmt->cTabCount != tmp.cTabCount)
|
||||
pFmt->dwMask &= ~PFM_TABSTOPS;
|
||||
else
|
||||
if (memcmp(pFmt->rgxTabs, tmp.rgxTabs, tmp.cTabCount*sizeof(int)))
|
||||
pFmt->dwMask &= ~PFM_TABSTOPS;
|
||||
}
|
||||
|
||||
if (para == para_end)
|
||||
return;
|
||||
para = para->member.para.next_para;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -64,6 +64,7 @@ IRichEditOle_fnQueryInterface(IRichEditOle *me, REFIID riid, LPVOID *ppvObj)
|
|||
*ppvObj = (LPVOID) This;
|
||||
return S_OK;
|
||||
}
|
||||
FIXME("%p: unhandled interface %s\n", This, debugstr_guid(riid) );
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
@ -215,7 +216,7 @@ static HRESULT WINAPI IRichEditOle_fnSetHostNames(IRichEditOle *me,
|
|||
LPCSTR lpstrContainerApp, LPCSTR lpstrContainerObj)
|
||||
{
|
||||
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
|
||||
FIXME("stub %p\n",This);
|
||||
FIXME("stub %p %s %s\n",This, lpstrContainerApp, lpstrContainerObj);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,365 +11,6 @@
|
|||
#include "richedit.h"
|
||||
|
||||
|
||||
/* The following defines are automatically generated. Do not edit. */
|
||||
|
||||
|
||||
/* These must be sequential beginning from zero */
|
||||
|
||||
#define rtfSC_nothing 0
|
||||
#define rtfSC_space 1
|
||||
#define rtfSC_exclam 2
|
||||
#define rtfSC_quotedbl 3
|
||||
#define rtfSC_numbersign 4
|
||||
#define rtfSC_dollar 5
|
||||
#define rtfSC_percent 6
|
||||
#define rtfSC_ampersand 7
|
||||
#define rtfSC_quoteright 8
|
||||
#define rtfSC_parenleft 9
|
||||
#define rtfSC_parenright 10
|
||||
#define rtfSC_asterisk 11
|
||||
#define rtfSC_plus 12
|
||||
#define rtfSC_comma 13
|
||||
#define rtfSC_hyphen 14
|
||||
#define rtfSC_period 15
|
||||
#define rtfSC_slash 16
|
||||
#define rtfSC_zero 17
|
||||
#define rtfSC_one 18
|
||||
#define rtfSC_two 19
|
||||
#define rtfSC_three 20
|
||||
#define rtfSC_four 21
|
||||
#define rtfSC_five 22
|
||||
#define rtfSC_six 23
|
||||
#define rtfSC_seven 24
|
||||
#define rtfSC_eight 25
|
||||
#define rtfSC_nine 26
|
||||
#define rtfSC_colon 27
|
||||
#define rtfSC_semicolon 28
|
||||
#define rtfSC_less 29
|
||||
#define rtfSC_equal 30
|
||||
#define rtfSC_greater 31
|
||||
#define rtfSC_question 32
|
||||
#define rtfSC_at 33
|
||||
#define rtfSC_A 34
|
||||
#define rtfSC_B 35
|
||||
#define rtfSC_C 36
|
||||
#define rtfSC_D 37
|
||||
#define rtfSC_E 38
|
||||
#define rtfSC_F 39
|
||||
#define rtfSC_G 40
|
||||
#define rtfSC_H 41
|
||||
#define rtfSC_I 42
|
||||
#define rtfSC_J 43
|
||||
#define rtfSC_K 44
|
||||
#define rtfSC_L 45
|
||||
#define rtfSC_M 46
|
||||
#define rtfSC_N 47
|
||||
#define rtfSC_O 48
|
||||
#define rtfSC_P 49
|
||||
#define rtfSC_Q 50
|
||||
#define rtfSC_R 51
|
||||
#define rtfSC_S 52
|
||||
#define rtfSC_T 53
|
||||
#define rtfSC_U 54
|
||||
#define rtfSC_V 55
|
||||
#define rtfSC_W 56
|
||||
#define rtfSC_X 57
|
||||
#define rtfSC_Y 58
|
||||
#define rtfSC_Z 59
|
||||
#define rtfSC_bracketleft 60
|
||||
#define rtfSC_backslash 61
|
||||
#define rtfSC_bracketright 62
|
||||
#define rtfSC_asciicircum 63
|
||||
#define rtfSC_underscore 64
|
||||
#define rtfSC_quoteleft 65
|
||||
#define rtfSC_a 66
|
||||
#define rtfSC_b 67
|
||||
#define rtfSC_c 68
|
||||
#define rtfSC_d 69
|
||||
#define rtfSC_e 70
|
||||
#define rtfSC_f 71
|
||||
#define rtfSC_g 72
|
||||
#define rtfSC_h 73
|
||||
#define rtfSC_i 74
|
||||
#define rtfSC_j 75
|
||||
#define rtfSC_k 76
|
||||
#define rtfSC_l 77
|
||||
#define rtfSC_m 78
|
||||
#define rtfSC_n 79
|
||||
#define rtfSC_o 80
|
||||
#define rtfSC_p 81
|
||||
#define rtfSC_q 82
|
||||
#define rtfSC_r 83
|
||||
#define rtfSC_s 84
|
||||
#define rtfSC_t 85
|
||||
#define rtfSC_u 86
|
||||
#define rtfSC_v 87
|
||||
#define rtfSC_w 88
|
||||
#define rtfSC_x 89
|
||||
#define rtfSC_y 90
|
||||
#define rtfSC_z 91
|
||||
#define rtfSC_braceleft 92
|
||||
#define rtfSC_bar 93
|
||||
#define rtfSC_braceright 94
|
||||
#define rtfSC_asciitilde 95
|
||||
#define rtfSC_exclamdown 96
|
||||
#define rtfSC_cent 97
|
||||
#define rtfSC_sterling 98
|
||||
#define rtfSC_fraction 99
|
||||
#define rtfSC_yen 100
|
||||
#define rtfSC_florin 101
|
||||
#define rtfSC_section 102
|
||||
#define rtfSC_currency 103
|
||||
#define rtfSC_quotedblleft 104
|
||||
#define rtfSC_guillemotleft 105
|
||||
#define rtfSC_guilsinglleft 106
|
||||
#define rtfSC_guilsinglright 107
|
||||
#define rtfSC_fi 108
|
||||
#define rtfSC_fl 109
|
||||
#define rtfSC_endash 110
|
||||
#define rtfSC_dagger 111
|
||||
#define rtfSC_daggerdbl 112
|
||||
#define rtfSC_periodcentered 113
|
||||
#define rtfSC_paragraph 114
|
||||
#define rtfSC_bullet 115
|
||||
#define rtfSC_quotesinglbase 116
|
||||
#define rtfSC_quotedblbase 117
|
||||
#define rtfSC_quotedblright 118
|
||||
#define rtfSC_guillemotright 119
|
||||
#define rtfSC_ellipsis 120
|
||||
#define rtfSC_perthousand 121
|
||||
#define rtfSC_questiondown 122
|
||||
#define rtfSC_grave 123
|
||||
#define rtfSC_acute 124
|
||||
#define rtfSC_circumflex 125
|
||||
#define rtfSC_tilde 126
|
||||
#define rtfSC_macron 127
|
||||
#define rtfSC_breve 128
|
||||
#define rtfSC_dotaccent 129
|
||||
#define rtfSC_dieresis 130
|
||||
#define rtfSC_ring 131
|
||||
#define rtfSC_cedilla 132
|
||||
#define rtfSC_hungarumlaut 133
|
||||
#define rtfSC_ogonek 134
|
||||
#define rtfSC_caron 135
|
||||
#define rtfSC_emdash 136
|
||||
#define rtfSC_AE 137
|
||||
#define rtfSC_ordfeminine 138
|
||||
#define rtfSC_Lslash 139
|
||||
#define rtfSC_Oslash 140
|
||||
#define rtfSC_OE 141
|
||||
#define rtfSC_ordmasculine 142
|
||||
#define rtfSC_ae 143
|
||||
#define rtfSC_dotlessi 144
|
||||
#define rtfSC_lslash 145
|
||||
#define rtfSC_oslash 146
|
||||
#define rtfSC_oe 147
|
||||
#define rtfSC_germandbls 148
|
||||
#define rtfSC_Aacute 149
|
||||
#define rtfSC_Acircumflex 150
|
||||
#define rtfSC_Adieresis 151
|
||||
#define rtfSC_Agrave 152
|
||||
#define rtfSC_Aring 153
|
||||
#define rtfSC_Atilde 154
|
||||
#define rtfSC_Ccedilla 155
|
||||
#define rtfSC_Eacute 156
|
||||
#define rtfSC_Ecircumflex 157
|
||||
#define rtfSC_Edieresis 158
|
||||
#define rtfSC_Egrave 159
|
||||
#define rtfSC_Eth 160
|
||||
#define rtfSC_Iacute 161
|
||||
#define rtfSC_Icircumflex 162
|
||||
#define rtfSC_Idieresis 163
|
||||
#define rtfSC_Igrave 164
|
||||
#define rtfSC_Ntilde 165
|
||||
#define rtfSC_Oacute 166
|
||||
#define rtfSC_Ocircumflex 167
|
||||
#define rtfSC_Odieresis 168
|
||||
#define rtfSC_Ograve 169
|
||||
#define rtfSC_Otilde 170
|
||||
#define rtfSC_Scaron 171
|
||||
#define rtfSC_Thorn 172
|
||||
#define rtfSC_Uacute 173
|
||||
#define rtfSC_Ucircumflex 174
|
||||
#define rtfSC_Udieresis 175
|
||||
#define rtfSC_Ugrave 176
|
||||
#define rtfSC_Yacute 177
|
||||
#define rtfSC_Ydieresis 178
|
||||
#define rtfSC_aacute 179
|
||||
#define rtfSC_acircumflex 180
|
||||
#define rtfSC_adieresis 181
|
||||
#define rtfSC_agrave 182
|
||||
#define rtfSC_aring 183
|
||||
#define rtfSC_atilde 184
|
||||
#define rtfSC_brokenbar 185
|
||||
#define rtfSC_ccedilla 186
|
||||
#define rtfSC_copyright 187
|
||||
#define rtfSC_degree 188
|
||||
#define rtfSC_divide 189
|
||||
#define rtfSC_eacute 190
|
||||
#define rtfSC_ecircumflex 191
|
||||
#define rtfSC_edieresis 192
|
||||
#define rtfSC_egrave 193
|
||||
#define rtfSC_eth 194
|
||||
#define rtfSC_iacute 195
|
||||
#define rtfSC_icircumflex 196
|
||||
#define rtfSC_idieresis 197
|
||||
#define rtfSC_igrave 198
|
||||
#define rtfSC_logicalnot 199
|
||||
#define rtfSC_minus 200
|
||||
#define rtfSC_multiply 201
|
||||
#define rtfSC_ntilde 202
|
||||
#define rtfSC_oacute 203
|
||||
#define rtfSC_ocircumflex 204
|
||||
#define rtfSC_odieresis 205
|
||||
#define rtfSC_ograve 206
|
||||
#define rtfSC_onehalf 207
|
||||
#define rtfSC_onequarter 208
|
||||
#define rtfSC_onesuperior 209
|
||||
#define rtfSC_otilde 210
|
||||
#define rtfSC_plusminus 211
|
||||
#define rtfSC_registered 212
|
||||
#define rtfSC_thorn 213
|
||||
#define rtfSC_threequarters 214
|
||||
#define rtfSC_threesuperior 215
|
||||
#define rtfSC_trademark 216
|
||||
#define rtfSC_twosuperior 217
|
||||
#define rtfSC_uacute 218
|
||||
#define rtfSC_ucircumflex 219
|
||||
#define rtfSC_udieresis 220
|
||||
#define rtfSC_ugrave 221
|
||||
#define rtfSC_yacute 222
|
||||
#define rtfSC_ydieresis 223
|
||||
#define rtfSC_Alpha 224
|
||||
#define rtfSC_Beta 225
|
||||
#define rtfSC_Chi 226
|
||||
#define rtfSC_Delta 227
|
||||
#define rtfSC_Epsilon 228
|
||||
#define rtfSC_Phi 229
|
||||
#define rtfSC_Gamma 230
|
||||
#define rtfSC_Eta 231
|
||||
#define rtfSC_Iota 232
|
||||
#define rtfSC_Kappa 233
|
||||
#define rtfSC_Lambda 234
|
||||
#define rtfSC_Mu 235
|
||||
#define rtfSC_Nu 236
|
||||
#define rtfSC_Omicron 237
|
||||
#define rtfSC_Pi 238
|
||||
#define rtfSC_Theta 239
|
||||
#define rtfSC_Rho 240
|
||||
#define rtfSC_Sigma 241
|
||||
#define rtfSC_Tau 242
|
||||
#define rtfSC_Upsilon 243
|
||||
#define rtfSC_varUpsilon 244
|
||||
#define rtfSC_Omega 245
|
||||
#define rtfSC_Xi 246
|
||||
#define rtfSC_Psi 247
|
||||
#define rtfSC_Zeta 248
|
||||
#define rtfSC_alpha 249
|
||||
#define rtfSC_beta 250
|
||||
#define rtfSC_chi 251
|
||||
#define rtfSC_delta 252
|
||||
#define rtfSC_epsilon 253
|
||||
#define rtfSC_phi 254
|
||||
#define rtfSC_varphi 255
|
||||
#define rtfSC_gamma 256
|
||||
#define rtfSC_eta 257
|
||||
#define rtfSC_iota 258
|
||||
#define rtfSC_kappa 259
|
||||
#define rtfSC_lambda 260
|
||||
#define rtfSC_mu 261
|
||||
#define rtfSC_nu 262
|
||||
#define rtfSC_omicron 263
|
||||
#define rtfSC_pi 264
|
||||
#define rtfSC_varpi 265
|
||||
#define rtfSC_theta 266
|
||||
#define rtfSC_vartheta 267
|
||||
#define rtfSC_rho 268
|
||||
#define rtfSC_sigma 269
|
||||
#define rtfSC_varsigma 270
|
||||
#define rtfSC_tau 271
|
||||
#define rtfSC_upsilon 272
|
||||
#define rtfSC_omega 273
|
||||
#define rtfSC_xi 274
|
||||
#define rtfSC_psi 275
|
||||
#define rtfSC_zeta 276
|
||||
#define rtfSC_nobrkspace 277
|
||||
#define rtfSC_nobrkhyphen 278
|
||||
#define rtfSC_lessequal 279
|
||||
#define rtfSC_greaterequal 280
|
||||
#define rtfSC_infinity 281
|
||||
#define rtfSC_integral 282
|
||||
#define rtfSC_notequal 283
|
||||
#define rtfSC_radical 284
|
||||
#define rtfSC_radicalex 285
|
||||
#define rtfSC_approxequal 286
|
||||
#define rtfSC_apple 287
|
||||
#define rtfSC_partialdiff 288
|
||||
#define rtfSC_opthyphen 289
|
||||
#define rtfSC_formula 290
|
||||
#define rtfSC_lozenge 291
|
||||
#define rtfSC_universal 292
|
||||
#define rtfSC_existential 293
|
||||
#define rtfSC_suchthat 294
|
||||
#define rtfSC_congruent 295
|
||||
#define rtfSC_therefore 296
|
||||
#define rtfSC_perpendicular 297
|
||||
#define rtfSC_minute 298
|
||||
#define rtfSC_club 299
|
||||
#define rtfSC_diamond 300
|
||||
#define rtfSC_heart 301
|
||||
#define rtfSC_spade 302
|
||||
#define rtfSC_arrowboth 303
|
||||
#define rtfSC_arrowleft 304
|
||||
#define rtfSC_arrowup 305
|
||||
#define rtfSC_arrowright 306
|
||||
#define rtfSC_arrowdown 307
|
||||
#define rtfSC_second 308
|
||||
#define rtfSC_proportional 309
|
||||
#define rtfSC_equivalence 310
|
||||
#define rtfSC_arrowvertex 311
|
||||
#define rtfSC_arrowhorizex 312
|
||||
#define rtfSC_carriagereturn 313
|
||||
#define rtfSC_aleph 314
|
||||
#define rtfSC_Ifraktur 315
|
||||
#define rtfSC_Rfraktur 316
|
||||
#define rtfSC_weierstrass 317
|
||||
#define rtfSC_circlemultiply 318
|
||||
#define rtfSC_circleplus 319
|
||||
#define rtfSC_emptyset 320
|
||||
#define rtfSC_intersection 321
|
||||
#define rtfSC_union 322
|
||||
#define rtfSC_propersuperset 323
|
||||
#define rtfSC_reflexsuperset 324
|
||||
#define rtfSC_notsubset 325
|
||||
#define rtfSC_propersubset 326
|
||||
#define rtfSC_reflexsubset 327
|
||||
#define rtfSC_element 328
|
||||
#define rtfSC_notelement 329
|
||||
#define rtfSC_angle 330
|
||||
#define rtfSC_gradient 331
|
||||
#define rtfSC_product 332
|
||||
#define rtfSC_logicaland 333
|
||||
#define rtfSC_logicalor 334
|
||||
#define rtfSC_arrowdblboth 335
|
||||
#define rtfSC_arrowdblleft 336
|
||||
#define rtfSC_arrowdblup 337
|
||||
#define rtfSC_arrowdblright 338
|
||||
#define rtfSC_arrowdbldown 339
|
||||
#define rtfSC_angleleft 340
|
||||
#define rtfSC_registersans 341
|
||||
#define rtfSC_copyrightsans 342
|
||||
#define rtfSC_trademarksans 343
|
||||
#define rtfSC_angleright 344
|
||||
#define rtfSC_mathplus 345
|
||||
#define rtfSC_mathminus 346
|
||||
#define rtfSC_mathasterisk 347
|
||||
#define rtfSC_mathnumbersign 348
|
||||
#define rtfSC_dotmath 349
|
||||
#define rtfSC_mathequal 350
|
||||
#define rtfSC_mathtilde 351
|
||||
|
||||
#define rtfSC_MaxChar 352
|
||||
/*
|
||||
* rtf.h - RTF document processing stuff. Release 1.10.
|
||||
*/
|
||||
|
@ -418,13 +59,7 @@
|
|||
*/
|
||||
|
||||
|
||||
# ifdef THINK_C
|
||||
# define rtfNoParam (-32768) /* 16-bit max. neg. value */
|
||||
# endif
|
||||
# ifndef rtfNoParam
|
||||
# define rtfNoParam (-1000000)
|
||||
# endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -546,7 +181,8 @@
|
|||
# define rtfIndexRange 71
|
||||
# define rtfTOC 72
|
||||
# define rtfNeXTGraphic 73
|
||||
# define rtfMaxDestination 74 /* highest dest + 1 */
|
||||
# define rtfGenerator 74
|
||||
# define rtfMaxDestination 75 /* highest dest + 1 */
|
||||
|
||||
# define rtfFontFamily 4
|
||||
# define rtfFFNil 0
|
||||
|
@ -624,6 +260,7 @@
|
|||
# define rtfNoWidthNonJoiner 56 /* new in 1.10 */
|
||||
# define rtfCurHeadPict 57 /* valid? */
|
||||
/*# define rtfCurAnnot 58*/ /* apparently not used */
|
||||
# define rtfUnicode 58 /* no better category*/
|
||||
|
||||
# define rtfStyleAttr 7
|
||||
# define rtfAdditive 0 /* new in 1.10 */
|
||||
|
@ -709,6 +346,8 @@
|
|||
# define rtfAnnotProtected 75 /* new in 1.10 */
|
||||
# define rtfRTLDoc 76 /* new in 1.10 */
|
||||
# define rtfLTRDoc 77 /* new in 1.10 */
|
||||
# define rtfAnsiCodePage 78
|
||||
# define rtfUTF8RTF 79
|
||||
|
||||
# define rtfSectAttr 9
|
||||
# define rtfSectDef 0
|
||||
|
@ -950,6 +589,7 @@
|
|||
# define rtfCharCharSet 33 /* new in 1.10 */
|
||||
# define rtfLanguage 34
|
||||
# define rtfGray 35
|
||||
# define rtfUnicodeLength 36
|
||||
|
||||
# define rtfPictAttr 13
|
||||
# define rtfMacQD 0
|
||||
|
@ -1287,20 +927,6 @@
|
|||
# define rtfLangTurkish 0x041f
|
||||
# define rtfLangUrdu 0x0420
|
||||
|
||||
/*
|
||||
* CharSet indices
|
||||
*/
|
||||
|
||||
# define rtfCSGeneral 0 /* general (default) charset */
|
||||
# define rtfCSSymbol 1 /* symbol charset */
|
||||
|
||||
/*
|
||||
* Flags for auto-charset-processing. Both are on by default.
|
||||
*/
|
||||
|
||||
# define rtfReadCharSet 0x01 /* auto-read charset files */
|
||||
# define rtfSwitchCharSet 0x02 /* auto-switch charset maps */
|
||||
|
||||
/*
|
||||
* Style types
|
||||
*/
|
||||
|
@ -1381,20 +1007,25 @@ struct RTFStyleElt
|
|||
|
||||
# define New(t) ((t *) RTFAlloc ((int) sizeof (t)))
|
||||
|
||||
/* maximum number of character values representable in a byte */
|
||||
|
||||
# define charSetSize 256
|
||||
|
||||
/* charset stack size */
|
||||
|
||||
# define maxCSStack 10
|
||||
/* Parser stack size */
|
||||
|
||||
# define maxStack 32
|
||||
|
||||
struct _RTF_Info;
|
||||
typedef struct _RTF_Info RTF_Info;
|
||||
|
||||
typedef void (*RTFFuncPtr) (RTF_Info *); /* generic function pointer */
|
||||
|
||||
|
||||
/* RTF parser stack element */
|
||||
struct tagRTFState {
|
||||
CHARFORMAT2W fmt;
|
||||
int codePage;
|
||||
int unicodeLength;
|
||||
};
|
||||
typedef struct tagRTFState RTFState;
|
||||
|
||||
|
||||
struct _RTF_Info {
|
||||
/*
|
||||
* Public variables (listed in rtf.h)
|
||||
|
@ -1434,55 +1065,26 @@ struct _RTF_Info {
|
|||
int prevChar;
|
||||
int bumpLine;
|
||||
|
||||
/* Document-wide attributes */
|
||||
RTFFont *fontList; /* these lists MUST be */
|
||||
RTFColor *colorList; /* initialized to NULL */
|
||||
RTFStyle *styleList;
|
||||
int ansiCodePage; /* ANSI codepage used in conversion to Unicode */
|
||||
|
||||
/* Character attributes */
|
||||
int unicodeLength; /* The length of ANSI representation of Unicode characters */
|
||||
int codePage; /* Current codepage for text conversion */
|
||||
|
||||
char *inputName;
|
||||
char *outputName;
|
||||
|
||||
EDITSTREAM editstream;
|
||||
char InputBuffer[0x1000];
|
||||
DWORD dwInputSize;
|
||||
DWORD dwInputUsed;
|
||||
ME_InStream *stream;
|
||||
|
||||
/* edit window to output to */
|
||||
HWND hwndEdit;
|
||||
|
||||
/*
|
||||
* These arrays are used to map RTF input character values onto the standard
|
||||
* character names represented by the values. Input character values are
|
||||
* used as indices into the arrays to produce standard character codes.
|
||||
*/
|
||||
|
||||
|
||||
char *genCharSetFile ;
|
||||
int genCharCode[charSetSize]; /* general */
|
||||
int haveGenCharSet;
|
||||
|
||||
char *symCharSetFile;
|
||||
int symCharCode[charSetSize]; /* symbol */
|
||||
int haveSymCharSet;
|
||||
|
||||
int curCharSet;
|
||||
int *curCharCode;
|
||||
|
||||
/*
|
||||
* By default, the reader is configured to handle charset mapping invisibly,
|
||||
* including reading the charset files and switching charset maps as necessary
|
||||
* for Symbol font.
|
||||
*/
|
||||
|
||||
int autoCharSetFlags;
|
||||
|
||||
/*
|
||||
* Stack for keeping track of charset map on group begin/end. This is
|
||||
* necessary because group termination reverts the font to the previous
|
||||
* value, which may implicitly change it.
|
||||
*/
|
||||
|
||||
int csStack[maxCSStack];
|
||||
int csTop;
|
||||
|
||||
ME_TextEditor *editor;
|
||||
ME_Style *style;
|
||||
|
||||
RTFFuncPtr ccb[rtfMaxClass]; /* class callbacks */
|
||||
|
||||
|
@ -1492,12 +1094,15 @@ struct _RTF_Info {
|
|||
|
||||
RTFFuncPtr panicProc;
|
||||
|
||||
FILE *(*libFileOpen) ();
|
||||
|
||||
char *outMap[rtfSC_MaxChar];
|
||||
|
||||
DWORD dwOutputCount;
|
||||
char OutputBuffer[0x1000];
|
||||
WCHAR OutputBuffer[0x1000];
|
||||
|
||||
DWORD dwCPOutputCount;
|
||||
DWORD dwMaxCPOutputCount;
|
||||
char *cpOutputBuffer;
|
||||
|
||||
RTFState stack[maxStack];
|
||||
int stackTop;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1506,6 +1111,7 @@ struct _RTF_Info {
|
|||
*/
|
||||
|
||||
void RTFInit (RTF_Info *);
|
||||
void RTFDestroy(RTF_Info *info);
|
||||
void RTFSetInputName (RTF_Info *, char *);
|
||||
char *RTFGetInputName (RTF_Info *);
|
||||
void RTFSetOutputName (RTF_Info *, char *);
|
||||
|
@ -1530,10 +1136,6 @@ int RTFCheckMM (RTF_Info *, int, int);
|
|||
RTFFont *RTFGetFont (RTF_Info *, int);
|
||||
RTFColor *RTFGetColor (RTF_Info *, int);
|
||||
RTFStyle *RTFGetStyle (RTF_Info *, int);
|
||||
# define RTFAlloc(size) _RTFAlloc ((int) size)
|
||||
char *_RTFAlloc (int);
|
||||
char *RTFStrSave (char *);
|
||||
void RTFFree (char *);
|
||||
int RTFCharToHex ( char);
|
||||
int RTFHexToChar ( int );
|
||||
void RTFSetMsgProc ( RTFFuncPtr );
|
||||
|
@ -1549,22 +1151,12 @@ void RTFSetPanicProc ( RTF_Info *, RTFFuncPtr);
|
|||
void RTFMsg (RTF_Info *, const char *fmt, ...);
|
||||
void RTFPanic (RTF_Info *, const char *fmt, ...);
|
||||
|
||||
int RTFReadOutputMap ( RTF_Info *, char *[], int);
|
||||
int RTFReadCharSetMap ( RTF_Info *, int);
|
||||
void RTFSetCharSetMap ( RTF_Info *, char *, int);
|
||||
int RTFStdCharCode ( RTF_Info *, const char *);
|
||||
const char *RTFStdCharName ( RTF_Info *, int);
|
||||
int RTFMapChar ( RTF_Info *, int);
|
||||
int RTFGetCharSet( RTF_Info * );
|
||||
void RTFSetCharSet( RTF_Info *, int);
|
||||
|
||||
void RTFSetOpenLibFileProc ( RTF_Info *, FILE *(*)());
|
||||
FILE *RTFOpenLibFile ( RTF_Info *, char *, char *);
|
||||
|
||||
void RTFFlushOutputBuffer( RTF_Info *info );
|
||||
void RTFSetEditStream(RTF_Info *, EDITSTREAM *es);
|
||||
void RTFSetEditStream(RTF_Info *info, ME_InStream *stream);
|
||||
|
||||
void WriterInit (RTF_Info *);
|
||||
int BeginFile (RTF_Info *);
|
||||
|
||||
int RTFCharSetToCodePage(RTF_Info *info, int charset);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,7 +26,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit);
|
|||
|
||||
int ME_CanJoinRuns(ME_Run *run1, ME_Run *run2)
|
||||
{
|
||||
if ((run1->nFlags | run2->nFlags) & (MERF_ENDPARA | MERF_GRAPHICS))
|
||||
if ((run1->nFlags | run2->nFlags) & MERF_NOJOIN)
|
||||
return 0;
|
||||
if (run1->style != run2->style)
|
||||
return 0;
|
||||
|
@ -91,8 +91,8 @@ void ME_CheckCharOffsets(ME_TextEditor *editor)
|
|||
ofs = 0;
|
||||
break;
|
||||
case diRun:
|
||||
TRACE("run, real ofs = %d (+ofsp = %d), counted = %d, len = %d, txt = \"%s\", flags=%08x, fx&mask = %08lx\n",
|
||||
p->member.run.nCharOfs, p->member.run.nCharOfs+ofsp, ofsp+ofs,
|
||||
TRACE("run, real ofs = %d (+ofsp = %d), counted = %d, len = %d, txt = \"%s\", flags=%08x, fx&mask = %08lx\n",
|
||||
p->member.run.nCharOfs, p->member.run.nCharOfs+ofsp, ofsp+ofs,
|
||||
p->member.run.strText->nLen, debugstr_w(p->member.run.strText->szData),
|
||||
p->member.run.nFlags,
|
||||
p->member.run.style->fmt.dwMask & p->member.run.style->fmt.dwEffects);
|
||||
|
@ -108,14 +108,14 @@ void ME_CheckCharOffsets(ME_TextEditor *editor)
|
|||
int ME_CharOfsFromRunOfs(ME_TextEditor *editor, ME_DisplayItem *pRun, int nOfs)
|
||||
{
|
||||
ME_DisplayItem *pPara;
|
||||
|
||||
|
||||
assert(pRun->type == diRun);
|
||||
assert(pRun->member.run.nCharOfs != -1);
|
||||
|
||||
pPara = ME_FindItemBack(pRun, diParagraph);
|
||||
assert(pPara);
|
||||
assert(pPara->type==diParagraph);
|
||||
return pPara->member.para.nCharOfs + pRun->member.run.nCharOfs
|
||||
return pPara->member.para.nCharOfs + pRun->member.run.nCharOfs
|
||||
+ ME_VPosToPos(pRun->member.run.strText, nOfs);
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **
|
|||
{
|
||||
ME_DisplayItem *pPara;
|
||||
int nParaOfs;
|
||||
|
||||
|
||||
pPara = editor->pBuffer->pFirst->member.para.next_para;
|
||||
assert(pPara);
|
||||
assert(ppRun);
|
||||
|
@ -137,18 +137,18 @@ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **
|
|||
{
|
||||
nParaOfs = pPara->member.para.nCharOfs;
|
||||
assert(nCharOfs >= nParaOfs);
|
||||
|
||||
|
||||
if (nCharOfs < pPara->member.para.next_para->member.para.nCharOfs)
|
||||
{
|
||||
*ppRun = ME_FindItemFwd(pPara, diRun);
|
||||
assert(*ppRun);
|
||||
assert(*ppRun);
|
||||
while (!((*ppRun)->member.run.nFlags & MERF_ENDPARA))
|
||||
{
|
||||
ME_DisplayItem *pNext = ME_FindItemFwd(*ppRun, diRun);
|
||||
assert(pNext);
|
||||
assert(pNext->type == diRun);
|
||||
if (nCharOfs < nParaOfs + pNext->member.run.nCharOfs) {
|
||||
*pOfs = ME_PosToVPos((*ppRun)->member.run.strText,
|
||||
*pOfs = ME_PosToVPos((*ppRun)->member.run.strText,
|
||||
nCharOfs - nParaOfs - (*ppRun)->member.run.nCharOfs);
|
||||
return;
|
||||
}
|
||||
|
@ -157,12 +157,12 @@ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **
|
|||
if (nCharOfs == nParaOfs + (*ppRun)->member.run.nCharOfs) {
|
||||
*pOfs = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
pPara = pPara->member.para.next_para;
|
||||
}
|
||||
*ppRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
|
||||
*pOfs = 0;
|
||||
*pOfs = 0;
|
||||
assert((*ppRun)->member.run.nFlags & MERF_ENDPARA);
|
||||
}
|
||||
|
||||
|
@ -174,13 +174,15 @@ void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p)
|
|||
assert(p->member.run.nCharOfs != -1);
|
||||
ME_GetParagraph(p)->member.para.nFlags |= MEPF_REWRAP;
|
||||
|
||||
if (editor->bCaretAtEnd && editor->pCursors[0].pRun == pNext)
|
||||
editor->bCaretAtEnd = FALSE;
|
||||
for (i=0; i<editor->nCursors; i++) {
|
||||
if (editor->pCursors[i].pRun == pNext) {
|
||||
editor->pCursors[i].pRun = p;
|
||||
editor->pCursors[i].nOffset += ME_StrVLen(p->member.run.strText);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ME_AppendString(p->member.run.strText, pNext->member.run.strText);
|
||||
ME_Remove(pNext);
|
||||
ME_DestroyDisplayItem(pNext);
|
||||
|
@ -198,7 +200,8 @@ ME_DisplayItem *ME_SplitRun(ME_Context *c, ME_DisplayItem *item, int nVChar)
|
|||
ME_TextEditor *editor = c->editor;
|
||||
ME_DisplayItem *item2 = NULL;
|
||||
ME_Run *run, *run2;
|
||||
|
||||
ME_Paragraph *para = &ME_GetParagraph(item)->member.para;
|
||||
|
||||
assert(item->member.run.nCharOfs != -1);
|
||||
if(TRACE_ON(richedit))
|
||||
{
|
||||
|
@ -213,28 +216,28 @@ ME_DisplayItem *ME_SplitRun(ME_Context *c, ME_DisplayItem *item, int nVChar)
|
|||
run->pt.x, run->pt.y);
|
||||
|
||||
item2 = ME_SplitRunSimple(editor, item, nVChar);
|
||||
|
||||
|
||||
run2 = &item2->member.run;
|
||||
|
||||
ME_CalcRunExtent(c, run);
|
||||
ME_CalcRunExtent(c, run2);
|
||||
|
||||
|
||||
ME_CalcRunExtent(c, para, run);
|
||||
ME_CalcRunExtent(c, para, run2);
|
||||
|
||||
run2->pt.x = run->pt.x+run->nWidth;
|
||||
run2->pt.y = run->pt.y;
|
||||
|
||||
|
||||
if(TRACE_ON(richedit))
|
||||
{
|
||||
TRACE("Before check after split\n");
|
||||
ME_CheckCharOffsets(editor);
|
||||
TRACE("After check after split\n");
|
||||
TRACE("After split: %s(%ld, %ld), %s(%ld, %ld)\n",
|
||||
TRACE("After split: %s(%ld, %ld), %s(%ld, %ld)\n",
|
||||
debugstr_w(run->strText->szData), run->pt.x, run->pt.y,
|
||||
debugstr_w(run2->strText->szData), run2->pt.x, run2->pt.y);
|
||||
}
|
||||
|
||||
return item2;
|
||||
}
|
||||
|
||||
|
||||
/* split a run starting from voffset */
|
||||
ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, int nVChar)
|
||||
{
|
||||
|
@ -244,22 +247,22 @@ ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, i
|
|||
int i;
|
||||
assert(nVChar > 0 && nVChar < ME_StrVLen(run->strText));
|
||||
assert(item->type == diRun);
|
||||
assert(!(item->member.run.nFlags & MERF_GRAPHICS));
|
||||
assert(!(item->member.run.nFlags & (MERF_GRAPHICS | MERF_TAB)));
|
||||
assert(item->member.run.nCharOfs != -1);
|
||||
|
||||
item2 = ME_MakeRun(run->style,
|
||||
item2 = ME_MakeRun(run->style,
|
||||
ME_VSplitString(run->strText, nVChar), run->nFlags&MERF_SPLITMASK);
|
||||
|
||||
|
||||
item2->member.run.nCharOfs = item->member.run.nCharOfs+
|
||||
ME_VPosToPos(item->member.run.strText, nVChar);
|
||||
|
||||
run2 = &item2->member.run;
|
||||
ME_InsertBefore(item->next, item2);
|
||||
|
||||
|
||||
ME_UpdateRunFlags(editor, run);
|
||||
ME_UpdateRunFlags(editor, run2);
|
||||
for (i=0; i<editor->nCursors; i++) {
|
||||
if (editor->pCursors[i].pRun == item &&
|
||||
if (editor->pCursors[i].pRun == item &&
|
||||
editor->pCursors[i].nOffset >= nVChar) {
|
||||
assert(item2->type == diRun);
|
||||
editor->pCursors[i].pRun = item2;
|
||||
|
@ -270,18 +273,6 @@ ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, i
|
|||
return item2;
|
||||
}
|
||||
|
||||
/* split the start and final whitespace into separate runs */
|
||||
/* returns the last run added */
|
||||
/*
|
||||
ME_DisplayItem *ME_SplitFurther(ME_TextEditor *editor, ME_DisplayItem *item)
|
||||
{
|
||||
int i, nVLen, nChanged;
|
||||
assert(item->type == diRun);
|
||||
assert(!(item->member.run.nFlags & MERF_GRAPHICS));
|
||||
return item;
|
||||
}
|
||||
*/
|
||||
|
||||
ME_DisplayItem *ME_MakeRun(ME_Style *s, ME_String *strData, int nFlags)
|
||||
{
|
||||
ME_DisplayItem *item = ME_MakeDI(diRun);
|
||||
|
@ -298,12 +289,14 @@ ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem
|
|||
ME_Cursor tmp;
|
||||
ME_DisplayItem *pDI;
|
||||
ME_UndoItem *pUI;
|
||||
|
||||
|
||||
assert(pItem->type == diRun || pItem->type == diUndoInsertRun);
|
||||
|
||||
|
||||
pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL);
|
||||
pUI->nStart = nCharOfs;
|
||||
pUI->nLen = pItem->member.run.strText->nLen;
|
||||
if (pUI) {
|
||||
pUI->nStart = nCharOfs;
|
||||
pUI->nLen = pItem->member.run.strText->nLen;
|
||||
}
|
||||
ME_CursorFromCharOfs(editor, nCharOfs, &tmp);
|
||||
if (tmp.nOffset) {
|
||||
tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset);
|
||||
|
@ -315,13 +308,8 @@ ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem
|
|||
TRACE("Shift length:%d\n", pDI->member.run.strText->nLen);
|
||||
ME_PropagateCharOffset(tmp.pRun, pDI->member.run.strText->nLen);
|
||||
ME_GetParagraph(tmp.pRun)->member.para.nFlags |= MEPF_REWRAP;
|
||||
|
||||
return pDI;
|
||||
}
|
||||
|
||||
static inline int ME_IsWSpace(WCHAR ch)
|
||||
{
|
||||
return ch <= ' ';
|
||||
return pDI;
|
||||
}
|
||||
|
||||
void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run)
|
||||
|
@ -331,19 +319,19 @@ void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run)
|
|||
run->nFlags |= MERF_SPLITTABLE;
|
||||
else
|
||||
run->nFlags &= ~MERF_SPLITTABLE;
|
||||
|
||||
if (!(run->nFlags & MERF_GRAPHICS)) {
|
||||
|
||||
if (!(run->nFlags & MERF_NOTEXT)) {
|
||||
if (ME_IsWhitespaces(run->strText))
|
||||
run->nFlags |= MERF_WHITESPACE | MERF_STARTWHITE | MERF_ENDWHITE;
|
||||
else
|
||||
{
|
||||
run->nFlags &= ~MERF_WHITESPACE;
|
||||
|
||||
|
||||
if (ME_IsWSpace(ME_GetCharFwd(run->strText,0)))
|
||||
run->nFlags |= MERF_STARTWHITE;
|
||||
else
|
||||
run->nFlags &= ~MERF_STARTWHITE;
|
||||
|
||||
|
||||
if (ME_IsWSpace(ME_GetCharBack(run->strText,0)))
|
||||
run->nFlags |= MERF_ENDWHITE;
|
||||
else
|
||||
|
@ -361,7 +349,7 @@ void ME_GetGraphicsSize(ME_TextEditor *editor, ME_Run *run, SIZE *pSize)
|
|||
pSize->cy = 64;
|
||||
}
|
||||
|
||||
int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run)
|
||||
int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Paragraph *para, ME_Run *run)
|
||||
{
|
||||
int fit = 0;
|
||||
HGDIOBJ hOldFont;
|
||||
|
@ -370,6 +358,12 @@ int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run)
|
|||
if (!run->strText->nLen)
|
||||
return 0;
|
||||
|
||||
if (run->nFlags & MERF_TAB)
|
||||
{
|
||||
if (cx < run->nWidth/2)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
if (run->nFlags & MERF_GRAPHICS)
|
||||
{
|
||||
SIZE sz;
|
||||
|
@ -380,9 +374,9 @@ int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run)
|
|||
}
|
||||
hDC = GetDC(editor->hWnd);
|
||||
hOldFont = ME_SelectStyleFont(editor, hDC, run->style);
|
||||
GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen,
|
||||
GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen,
|
||||
cx, &fit, NULL, &sz);
|
||||
ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);
|
||||
ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);
|
||||
ReleaseDC(editor->hWnd, hDC);
|
||||
return fit;
|
||||
}
|
||||
|
@ -396,6 +390,12 @@ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run)
|
|||
if (!run->strText->nLen)
|
||||
return 0;
|
||||
|
||||
if (run->nFlags & MERF_TAB)
|
||||
{
|
||||
if (cx < run->nWidth/2)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
if (run->nFlags & MERF_GRAPHICS)
|
||||
{
|
||||
SIZE sz;
|
||||
|
@ -407,19 +407,19 @@ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run)
|
|||
|
||||
hDC = GetDC(editor->hWnd);
|
||||
hOldFont = ME_SelectStyleFont(editor, hDC, run->style);
|
||||
GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen,
|
||||
GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen,
|
||||
cx, &fit, NULL, &sz);
|
||||
if (fit != run->strText->nLen)
|
||||
{
|
||||
int chars = 1;
|
||||
|
||||
|
||||
GetTextExtentPoint32W(hDC, run->strText->szData, fit, &sz2);
|
||||
fit1 = ME_StrRelPos(run->strText, fit, &chars);
|
||||
GetTextExtentPoint32W(hDC, run->strText->szData, fit1, &sz3);
|
||||
if (cx >= (sz2.cx+sz3.cx)/2)
|
||||
fit = fit1;
|
||||
}
|
||||
ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);
|
||||
ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);
|
||||
ReleaseDC(editor->hWnd, hDC);
|
||||
return fit;
|
||||
}
|
||||
|
@ -429,7 +429,7 @@ int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset)
|
|||
SIZE size;
|
||||
HDC hDC = GetDC(editor->hWnd);
|
||||
HGDIOBJ hOldFont;
|
||||
|
||||
|
||||
if (pRun->nFlags & MERF_GRAPHICS)
|
||||
{
|
||||
if (!nOffset) return 0;
|
||||
|
@ -438,56 +438,88 @@ int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset)
|
|||
}
|
||||
hOldFont = ME_SelectStyleFont(editor, hDC, pRun->style);
|
||||
GetTextExtentPoint32W(hDC, pRun->strText->szData, nOffset, &size);
|
||||
ME_UnselectStyleFont(editor, hDC, pRun->style, hOldFont);
|
||||
ME_UnselectStyleFont(editor, hDC, pRun->style, hOldFont);
|
||||
ReleaseDC(editor->hWnd, hDC);
|
||||
return size.cx;
|
||||
}
|
||||
|
||||
void ME_GetTextExtent(ME_Context *c, LPCWSTR szText, int nChars, ME_Style *s,
|
||||
void ME_GetTextExtent(ME_Context *c, LPCWSTR szText, int nChars, ME_Style *s,
|
||||
SIZE *size)
|
||||
{
|
||||
HDC hDC = c->hDC;
|
||||
HGDIOBJ hOldFont;
|
||||
hOldFont = ME_SelectStyleFont(c->editor, hDC, s);
|
||||
GetTextExtentPoint32W(hDC, szText, nChars, size);
|
||||
ME_UnselectStyleFont(c->editor, hDC, s, hOldFont);
|
||||
ME_UnselectStyleFont(c->editor, hDC, s, hOldFont);
|
||||
}
|
||||
|
||||
SIZE ME_GetRunSize(ME_Context *c, ME_Run *run, int nLen)
|
||||
SIZE ME_GetRunSizeCommon(ME_Context *c, ME_Paragraph *para, ME_Run *run, int nLen, int *pAscent, int *pDescent)
|
||||
{
|
||||
SIZE size;
|
||||
int nMaxLen = ME_StrVLen(run->strText);
|
||||
|
||||
if (nLen>nMaxLen)
|
||||
nLen = nMaxLen;
|
||||
|
||||
|
||||
/* FIXME the following call also ensures that TEXTMETRIC structure is filled
|
||||
* this is wasteful for graphics and TAB runs, but that shouldn't matter
|
||||
* in practice
|
||||
*/
|
||||
ME_GetTextExtent(c, run->strText->szData, nLen, run->style, &size);
|
||||
assert(run->style->tm.tmAscent>0);
|
||||
assert(run->style->tm.tmDescent>0);
|
||||
*pAscent = run->style->tm.tmAscent;
|
||||
*pDescent = run->style->tm.tmDescent;
|
||||
size.cy = *pAscent + *pDescent;
|
||||
|
||||
if (run->nFlags & MERF_TAB)
|
||||
{
|
||||
int pos = 0, i = 0, ppos;
|
||||
int lpsx = GetDeviceCaps(c->hDC, LOGPIXELSX);
|
||||
PARAFORMAT2 *pFmt = para->pFmt;
|
||||
do {
|
||||
if (i < pFmt->cTabCount)
|
||||
{
|
||||
pos = pFmt->rgxTabs[i]&0x00FFFFFF;
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos += 720-(pos%720);
|
||||
}
|
||||
ppos = pos*lpsx/1440;
|
||||
if (ppos>run->pt.x) {
|
||||
size.cx = ppos - run->pt.x;
|
||||
break;
|
||||
}
|
||||
} while(1);
|
||||
size.cy = *pAscent + *pDescent;
|
||||
return size;
|
||||
}
|
||||
if (run->nFlags & MERF_GRAPHICS)
|
||||
{
|
||||
ME_GetGraphicsSize(c->editor, run, &size);
|
||||
if (size.cy > *pAscent)
|
||||
*pAscent = size.cy;
|
||||
/* descent is unchanged */
|
||||
return size;
|
||||
}
|
||||
|
||||
ME_GetTextExtent(c, run->strText->szData, nLen, run->style, &size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void ME_CalcRunExtent(ME_Context *c, ME_Run *run)
|
||||
SIZE ME_GetRunSize(ME_Context *c, ME_Paragraph *para, ME_Run *run, int nLen)
|
||||
{
|
||||
int asc, desc;
|
||||
return ME_GetRunSizeCommon(c, para, run, nLen, &asc, &desc);
|
||||
}
|
||||
|
||||
void ME_CalcRunExtent(ME_Context *c, ME_Paragraph *para, ME_Run *run)
|
||||
{
|
||||
SIZE size;
|
||||
int nEnd = ME_StrVLen(run->strText);
|
||||
|
||||
if (run->nFlags & MERF_GRAPHICS) {
|
||||
ME_GetGraphicsSize(c->editor, run, &size);
|
||||
run->nWidth = size.cx;
|
||||
run->nAscent = size.cy;
|
||||
run->nDescent = 0;
|
||||
return;
|
||||
}
|
||||
ME_GetTextExtent(c, run->strText->szData, nEnd, run->style, &size);
|
||||
SIZE size = ME_GetRunSizeCommon(c, para, run, nEnd, &run->nAscent, &run->nDescent);
|
||||
run->nWidth = size.cx;
|
||||
run->nAscent = run->style->tm.tmAscent;
|
||||
run->nDescent = run->style->tm.tmDescent;
|
||||
assert(size.cx);
|
||||
}
|
||||
|
||||
void ME_MustBeWrapped(ME_Context *c, ME_DisplayItem *para)
|
||||
|
@ -517,7 +549,7 @@ void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W
|
|||
{
|
||||
ME_Cursor tmp, tmp2;
|
||||
ME_DisplayItem *para;
|
||||
|
||||
|
||||
ME_CursorFromCharOfs(editor, nOfs, &tmp);
|
||||
if (tmp.nOffset)
|
||||
tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset);
|
||||
|
@ -528,7 +560,7 @@ void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W
|
|||
|
||||
para = ME_GetParagraph(tmp.pRun);
|
||||
para->member.para.nFlags |= MEPF_REWRAP;
|
||||
|
||||
|
||||
while(tmp.pRun != tmp2.pRun)
|
||||
{
|
||||
ME_UndoItem *undo = NULL;
|
||||
|
@ -559,9 +591,9 @@ void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W
|
|||
|
||||
void ME_SetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *mod)
|
||||
{
|
||||
ME_Style *style;
|
||||
ME_Style *style;
|
||||
ME_UndoItem *undo;
|
||||
|
||||
|
||||
assert(mod->cbSize == sizeof(CHARFORMAT2W));
|
||||
undo = ME_AddUndoItem(editor, diUndoSetDefaultCharFormat, NULL);
|
||||
if (undo) {
|
||||
|
@ -607,10 +639,10 @@ void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nTo, CHARFORMAT2W *p
|
|||
ME_DisplayItem *run, *run_end;
|
||||
int nOffset, nOffset2;
|
||||
CHARFORMAT2W tmp;
|
||||
|
||||
|
||||
if (nTo>nFrom) /* selection consists of chars from nFrom up to nTo-1 */
|
||||
nTo--;
|
||||
|
||||
|
||||
ME_RunOfsFromCharOfs(editor, nFrom, &run, &nOffset);
|
||||
if (nFrom == nTo) /* special case - if selection is empty, take previous char's formatting */
|
||||
{
|
||||
|
@ -626,22 +658,22 @@ void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nTo, CHARFORMAT2W *p
|
|||
return;
|
||||
}
|
||||
ME_RunOfsFromCharOfs(editor, nTo, &run_end, &nOffset2);
|
||||
|
||||
|
||||
ME_GetRunCharFormat(editor, run, pFmt);
|
||||
|
||||
|
||||
if (run == run_end) return;
|
||||
|
||||
|
||||
do {
|
||||
/* FIXME add more style feature comparisons */
|
||||
int nAttribs = CFM_SIZE | CFM_FACE | CFM_COLOR;
|
||||
int nEffects = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE;
|
||||
|
||||
run = ME_FindItemFwd(run, diRun);
|
||||
|
||||
|
||||
ZeroMemory(&tmp, sizeof(tmp));
|
||||
tmp.cbSize = sizeof(tmp);
|
||||
ME_GetRunCharFormat(editor, run, &tmp);
|
||||
|
||||
|
||||
assert((tmp.dwMask & nAttribs) == nAttribs);
|
||||
assert((tmp.dwMask & nEffects) == nEffects);
|
||||
/* reset flags that differ */
|
||||
|
@ -665,8 +697,8 @@ void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nTo, CHARFORMAT2W *p
|
|||
pFmt->dwMask &= ~CFM_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pFmt->dwMask &= ~((pFmt->dwEffects ^ tmp.dwEffects) & nEffects);
|
||||
|
||||
|
||||
} while(run != run_end);
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ int ME_IsWhitespaces(ME_String *s)
|
|||
{
|
||||
/* FIXME multibyte */
|
||||
WCHAR *pos = s->szData;
|
||||
while(*pos++ == ' ')
|
||||
while(ME_IsWSpace(*pos++))
|
||||
;
|
||||
pos--;
|
||||
if (*pos)
|
||||
|
@ -123,15 +123,14 @@ int ME_IsWhitespaces(ME_String *s)
|
|||
|
||||
int ME_IsSplitable(ME_String *s)
|
||||
{
|
||||
/* FIXME multibyte */
|
||||
WCHAR *pos = s->szData;
|
||||
WCHAR ch;
|
||||
while(*pos++ == L' ')
|
||||
while(ME_IsWSpace(*pos++))
|
||||
;
|
||||
pos--;
|
||||
while((ch = *pos++) != 0)
|
||||
{
|
||||
if (ch == L' ')
|
||||
if (ME_IsWSpace(ch))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -255,7 +254,7 @@ int ME_GetCharBack(ME_String *s, int nPos)
|
|||
|
||||
int ME_FindNonWhitespaceV(ME_String *s, int nVChar) {
|
||||
int i;
|
||||
for (i = nVChar; isspace(s->szData[i]) && i<s->nLen; i++)
|
||||
for (i = nVChar; i<s->nLen && ME_IsWSpace(s->szData[i]); i++)
|
||||
;
|
||||
|
||||
return i;
|
||||
|
@ -264,7 +263,7 @@ int ME_FindNonWhitespaceV(ME_String *s, int nVChar) {
|
|||
/* note: returns offset of the first trailing whitespace */
|
||||
int ME_ReverseFindNonWhitespaceV(ME_String *s, int nVChar) {
|
||||
int i;
|
||||
for (i = nVChar; i>0 && isspace(s->szData[i-1]); i--)
|
||||
for (i = nVChar; i>0 && ME_IsWSpace(s->szData[i-1]); i--)
|
||||
;
|
||||
|
||||
return i;
|
||||
|
@ -273,7 +272,7 @@ int ME_ReverseFindNonWhitespaceV(ME_String *s, int nVChar) {
|
|||
/* note: returns offset of the first trailing nonwhitespace */
|
||||
int ME_ReverseFindWhitespaceV(ME_String *s, int nVChar) {
|
||||
int i;
|
||||
for (i = nVChar; i>0 && !isspace(s->szData[i-1]); i--)
|
||||
for (i = nVChar; i>0 && !ME_IsWSpace(s->szData[i-1]); i--)
|
||||
;
|
||||
|
||||
return i;
|
||||
|
|
|
@ -54,7 +54,7 @@ CHARFORMAT2W *ME_ToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from)
|
|||
if (f->dwMask & CFM_FACE)
|
||||
MultiByteToWideChar(0, 0, f->szFaceName, -1, to->szFaceName, sizeof(to->szFaceName));
|
||||
/* copy the rest of the 2A structure to 2W */
|
||||
CopyMemory(1+((CHARFORMATW *)from), f+1, sizeof(CHARFORMAT2A)-sizeof(CHARFORMATA));
|
||||
CopyMemory(1+((CHARFORMATW *)to), f+1, sizeof(CHARFORMAT2A)-sizeof(CHARFORMATA));
|
||||
to->cbSize = sizeof(CHARFORMAT2W);
|
||||
return to;
|
||||
}
|
||||
|
@ -124,6 +124,7 @@ ME_Style *ME_MakeStyle(CHARFORMAT2W *style) {
|
|||
s->nSequence = -2;
|
||||
s->nRefs = 1;
|
||||
s->hFont = NULL;
|
||||
s->tm.tmAscent = -1;
|
||||
all_refs++;
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,9 @@ void ME_EmptyUndoStack(ME_TextEditor *editor)
|
|||
{
|
||||
ME_DisplayItem *p, *pNext;
|
||||
|
||||
if (editor->nUndoMode == umIgnore)
|
||||
return;
|
||||
|
||||
TRACE("Emptying undo stack\n");
|
||||
|
||||
p = editor->pUndoStack;
|
||||
|
@ -121,6 +124,10 @@ ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, ME_DisplayIte
|
|||
}
|
||||
|
||||
void ME_CommitUndo(ME_TextEditor *editor) {
|
||||
|
||||
if (editor->nUndoMode == umIgnore)
|
||||
return;
|
||||
|
||||
assert(editor->nUndoMode == umAddToUndo);
|
||||
|
||||
/* no transactions, no need to commit */
|
||||
|
@ -140,6 +147,8 @@ 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)
|
||||
|
@ -202,6 +211,8 @@ void ME_Undo(ME_TextEditor *editor) {
|
|||
ME_DisplayItem *p;
|
||||
ME_UndoMode nMode = editor->nUndoMode;
|
||||
|
||||
if (editor->nUndoMode == umIgnore)
|
||||
return;
|
||||
assert(nMode == umAddToUndo || nMode == umIgnore);
|
||||
|
||||
/* no undo items ? */
|
||||
|
@ -235,6 +246,8 @@ void ME_Redo(ME_TextEditor *editor) {
|
|||
|
||||
assert(nMode == umAddToUndo || nMode == umIgnore);
|
||||
|
||||
if (editor->nUndoMode == umIgnore)
|
||||
return;
|
||||
/* no redo items ? */
|
||||
if (!editor->pRedoStack)
|
||||
return;
|
||||
|
|
|
@ -26,16 +26,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit);
|
|||
|
||||
/*
|
||||
* Unsolved problems:
|
||||
*
|
||||
*
|
||||
* - center and right align in WordPad omits all spaces at the start, we don't
|
||||
* - objects/images are not handled yet
|
||||
* - no tabs
|
||||
*/
|
||||
|
||||
* - no tabs
|
||||
*/
|
||||
|
||||
ME_DisplayItem *ME_MakeRow(int height, int baseline, int width)
|
||||
{
|
||||
ME_DisplayItem *item = ME_MakeDI(diStartRow);
|
||||
|
||||
|
||||
item->member.row.nHeight = height;
|
||||
item->member.row.nBaseline = baseline;
|
||||
item->member.row.nWidth = width;
|
||||
|
@ -49,7 +49,7 @@ void ME_BeginRow(ME_WrapContext *wc)
|
|||
wc->pLastSplittableRun = NULL;
|
||||
wc->nAvailWidth = wc->nTotalWidth - (wc->nRow ? wc->nLeftMargin : wc->nFirstMargin) - wc->nRightMargin;
|
||||
wc->pt.x = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ME_InsertRowStart(ME_WrapContext *wc, ME_DisplayItem *pEnd)
|
||||
{
|
||||
|
@ -95,7 +95,7 @@ void ME_WrapEndParagraph(ME_WrapContext *wc, ME_DisplayItem *p)
|
|||
{
|
||||
if (wc->pRowStart)
|
||||
ME_InsertRowStart(wc, p->next);
|
||||
|
||||
|
||||
/*
|
||||
p = p->member.para.prev_para->next;
|
||||
while(p) {
|
||||
|
@ -109,15 +109,15 @@ void ME_WrapEndParagraph(ME_WrapContext *wc, ME_DisplayItem *p)
|
|||
p = p->next;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
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, &p->member.run);
|
||||
|
||||
ME_CalcRunExtent(wc->context, &ME_GetParagraph(p)->member.para, &p->member.run);
|
||||
}
|
||||
|
||||
ME_DisplayItem *ME_MaximizeSplit(ME_WrapContext *wc, ME_DisplayItem *p, int i)
|
||||
|
@ -139,7 +139,7 @@ ME_DisplayItem *ME_MaximizeSplit(ME_WrapContext *wc, ME_DisplayItem *p, int i)
|
|||
while(piter != wc->pRowStart)
|
||||
{
|
||||
piter = ME_FindItemBack(piter, diRun);
|
||||
if (piter->member.run.nFlags & MERF_WHITESPACE)
|
||||
if (piter->member.run.nFlags & MERF_WHITESPACE)
|
||||
{
|
||||
pp = piter;
|
||||
continue;
|
||||
|
@ -167,8 +167,8 @@ ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, in
|
|||
ME_DisplayItem *piter = p, *pp;
|
||||
int i, idesp, len;
|
||||
ME_Run *run = &p->member.run;
|
||||
|
||||
idesp = i = ME_CharFromPoint(wc->context->editor, loc, run);
|
||||
|
||||
idesp = i = ME_CharFromPoint(wc->context->editor, loc, &ME_GetParagraph(p)->member.para, run);
|
||||
len = ME_StrVLen(run->strText);
|
||||
assert(len>0);
|
||||
assert(i<len);
|
||||
|
@ -182,7 +182,7 @@ ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, in
|
|||
TRACE("Must backtrack to split at: %s\n", debugstr_w(p->member.run.strText->szData));
|
||||
if (wc->pLastSplittableRun)
|
||||
{
|
||||
if (wc->pLastSplittableRun->member.run.nFlags & MERF_GRAPHICS)
|
||||
if (wc->pLastSplittableRun->member.run.nFlags & (MERF_GRAPHICS|MERF_TAB))
|
||||
{
|
||||
wc->pt = wc->ptLastSplittableRun;
|
||||
return wc->pLastSplittableRun;
|
||||
|
@ -193,7 +193,7 @@ ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, in
|
|||
they serve no other purpose */
|
||||
ME_UpdateRunFlags(wc->context->editor, run);
|
||||
assert((wc->pLastSplittableRun->member.run.nFlags & MERF_SPLITTABLE));
|
||||
|
||||
|
||||
piter = wc->pLastSplittableRun;
|
||||
run = &piter->member.run;
|
||||
len = ME_StrVLen(run->strText);
|
||||
|
@ -201,7 +201,7 @@ ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, in
|
|||
i = ME_ReverseFindWhitespaceV(run->strText, len);
|
||||
if (i == len)
|
||||
i = ME_ReverseFindNonWhitespaceV(run->strText, len);
|
||||
if (i) {
|
||||
if (i) {
|
||||
ME_DisplayItem *piter2 = ME_SplitRun(wc->context, piter, i);
|
||||
wc->pt = piter2->member.run.pt;
|
||||
return piter2;
|
||||
|
@ -239,7 +239,7 @@ ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, in
|
|||
}
|
||||
/* the run is one char, can't split it */
|
||||
return piter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
|
||||
|
@ -248,24 +248,24 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
|
|||
ME_Run *run;
|
||||
int len;
|
||||
|
||||
assert(p->type == diRun);
|
||||
assert(p->type == diRun);
|
||||
if (!wc->pRowStart)
|
||||
wc->pRowStart = p;
|
||||
ME_WrapSizeRun(wc, p);
|
||||
run = &p->member.run;
|
||||
run->pt.x = wc->pt.x;
|
||||
run->pt.y = wc->pt.y;
|
||||
len = ME_StrVLen(run->strText);
|
||||
|
||||
ME_WrapSizeRun(wc, p);
|
||||
len = ME_StrVLen(run->strText);
|
||||
|
||||
if (wc->bOverflown) /* just skipping final whitespaces */
|
||||
{
|
||||
if (run->nFlags & MERF_WHITESPACE) {
|
||||
{
|
||||
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;
|
||||
|
@ -274,10 +274,6 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
|
|||
wc->bOverflown = FALSE;
|
||||
pp = ME_SplitRun(wc->context, p, black);
|
||||
p->member.run.nFlags |= MERF_SKIPPED;
|
||||
/*
|
||||
run->pt = wc->pt;
|
||||
wc->pt.x += run->nWidth;
|
||||
*/
|
||||
ME_InsertRowStart(wc, pp);
|
||||
return pp;
|
||||
}
|
||||
|
@ -290,15 +286,15 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
|
|||
/* will current run fit? */
|
||||
if (wc->pt.x + run->nWidth > wc->nAvailWidth)
|
||||
{
|
||||
int loc = wc->nAvailWidth - wc->pt.x;
|
||||
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;
|
||||
}
|
||||
/* graphics - we can split before */
|
||||
if (run->nFlags & MERF_GRAPHICS) {
|
||||
/* graphics or TAB - we can split before */
|
||||
if (run->nFlags & (MERF_GRAPHICS|MERF_TAB)) {
|
||||
wc->bOverflown = TRUE;
|
||||
return p;
|
||||
}
|
||||
|
@ -330,8 +326,8 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
|
|||
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) && (p != wc->pRowStart)))
|
||||
if ((run->nFlags & (MERF_SPLITTABLE | MERF_STARTWHITE))
|
||||
|| ((run->nFlags & (MERF_GRAPHICS|MERF_TAB)) && (p != wc->pRowStart)))
|
||||
{
|
||||
wc->pLastSplittableRun = p;
|
||||
wc->ptLastSplittableRun = wc->pt;
|
||||
|
@ -339,20 +335,24 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
|
|||
wc->pt.x += run->nWidth;
|
||||
return p->next;
|
||||
}
|
||||
|
||||
|
||||
void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) {
|
||||
ME_DisplayItem *p;
|
||||
ME_WrapContext wc;
|
||||
int dpi = GetDeviceCaps(c->hDC, LOGPIXELSX);
|
||||
|
||||
assert(tp->type == diParagraph);
|
||||
assert(tp->type == diParagraph);
|
||||
if (!(tp->member.para.nFlags & MEPF_REWRAP)) {
|
||||
return;
|
||||
}
|
||||
ME_PrepareParagraphForWrapping(c, tp);
|
||||
|
||||
|
||||
wc.context = c;
|
||||
/* wc.para_style = tp->member.para.style; */
|
||||
wc.style = NULL;
|
||||
tp->member.para.nRightMargin = tp->member.para.pFmt->dxRightIndent*dpi/1440;
|
||||
tp->member.para.nFirstMargin = tp->member.para.pFmt->dxStartIndent*dpi/1440;
|
||||
tp->member.para.nLeftMargin = (tp->member.para.pFmt->dxStartIndent+tp->member.para.pFmt->dxOffset)*dpi/1440;
|
||||
wc.nFirstMargin = tp->member.para.nFirstMargin;
|
||||
wc.nLeftMargin = tp->member.para.nLeftMargin;
|
||||
wc.nRightMargin = tp->member.para.nRightMargin;
|
||||
|
@ -362,7 +362,7 @@ void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) {
|
|||
wc.nTotalWidth = c->rcView.right - c->rcView.left;
|
||||
wc.nAvailWidth = wc.nTotalWidth - wc.nFirstMargin - wc.nRightMargin;
|
||||
wc.pRowStart = NULL;
|
||||
|
||||
|
||||
ME_BeginRow(&wc);
|
||||
for (p = tp->next; p!=tp->member.para.next_para; ) {
|
||||
assert(p->type != diStartRow);
|
||||
|
@ -413,37 +413,41 @@ void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp) {
|
|||
}
|
||||
}
|
||||
|
||||
void ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
|
||||
BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
|
||||
HWND hWnd = editor->hWnd;
|
||||
HDC hDC = GetDC(hWnd);
|
||||
ME_DisplayItem *item;
|
||||
ME_Context c;
|
||||
|
||||
BOOL bModified = FALSE;
|
||||
|
||||
ME_InitContext(&c, editor, hDC);
|
||||
c.pt.x = 0;
|
||||
c.pt.y = 0;
|
||||
item = editor->pBuffer->pFirst->next;
|
||||
while(item != editor->pBuffer->pLast) {
|
||||
BOOL bRedraw = FALSE;
|
||||
|
||||
|
||||
assert(item->type == diParagraph);
|
||||
if ((item->member.para.nFlags & MEPF_REWRAP)
|
||||
|| (item->member.para.nYPos != c.pt.y))
|
||||
bRedraw = TRUE;
|
||||
item->member.para.nYPos = c.pt.y;
|
||||
|
||||
|
||||
ME_WrapTextParagraph(&c, item);
|
||||
|
||||
if (bRedraw)
|
||||
item->member.para.nFlags |= MEPF_REPAINT;
|
||||
|
||||
bModified = bModified | bRedraw;
|
||||
|
||||
c.pt.y += item->member.para.nHeight;
|
||||
item = item->member.para.next_para;
|
||||
}
|
||||
editor->sizeWindow.cx = c.rcView.right-c.rcView.left;
|
||||
editor->sizeWindow.cy = c.rcView.bottom-c.rcView.top;
|
||||
editor->nTotalLength = c.pt.y;
|
||||
|
||||
|
||||
ME_DestroyContext(&c);
|
||||
ReleaseDC(hWnd, hDC);
|
||||
return bModified;
|
||||
}
|
||||
|
|
787
reactos/lib/riched20/writer.c
Normal file
787
reactos/lib/riched20/writer.c
Normal file
|
@ -0,0 +1,787 @@
|
|||
/*
|
||||
* RichEdit - RTF writer module
|
||||
*
|
||||
* Copyright 2005 by Phil Krylov
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "editor.h"
|
||||
#include "rtf.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(richedit);
|
||||
|
||||
|
||||
static BOOL
|
||||
ME_StreamOutRTFText(ME_TextEditor *editor, WCHAR *text, LONG nChars);
|
||||
|
||||
|
||||
static void
|
||||
ME_StreamOutInit(ME_TextEditor *editor, EDITSTREAM *stream)
|
||||
{
|
||||
editor->pStream = ALLOC_OBJ(ME_OutStream);
|
||||
editor->pStream->stream = stream;
|
||||
editor->pStream->pos = 0;
|
||||
editor->pStream->written = 0;
|
||||
editor->pStream->nFontTblLen = 0;
|
||||
editor->pStream->nColorTblLen = 1;
|
||||
}
|
||||
|
||||
|
||||
static BOOL
|
||||
ME_StreamOutFlush(ME_TextEditor *editor)
|
||||
{
|
||||
LONG nStart = 0;
|
||||
LONG nWritten = 0;
|
||||
EDITSTREAM *stream = editor->pStream->stream;
|
||||
|
||||
do {
|
||||
stream->dwError = stream->pfnCallback(stream->dwCookie, editor->pStream->buffer + nStart,
|
||||
editor->pStream->pos - nStart, &nWritten);
|
||||
if (nWritten == 0 || stream->dwError)
|
||||
return FALSE;
|
||||
editor->pStream->written += nWritten;
|
||||
nStart += nWritten;
|
||||
} while (nStart < editor->pStream->pos);
|
||||
editor->pStream->pos = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static LONG
|
||||
ME_StreamOutFree(ME_TextEditor *editor)
|
||||
{
|
||||
LONG written = editor->pStream->written;
|
||||
|
||||
FREE_OBJ(editor->pStream);
|
||||
editor->pStream = NULL;
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
static BOOL
|
||||
ME_StreamOutMove(ME_TextEditor *editor, BYTE *buffer, int len)
|
||||
{
|
||||
ME_OutStream *pStream = editor->pStream;
|
||||
|
||||
while (len) {
|
||||
int space = STREAMOUT_BUFFER_SIZE - pStream->pos;
|
||||
int fit = min(space, len);
|
||||
|
||||
TRACE("%u:%u:%.*s\n", pStream->pos, fit, fit, buffer);
|
||||
memmove(pStream->buffer + pStream->pos, buffer, fit);
|
||||
len -= fit;
|
||||
buffer += fit;
|
||||
pStream->pos += fit;
|
||||
if (pStream->pos == STREAMOUT_BUFFER_SIZE) {
|
||||
if (!ME_StreamOutFlush(editor))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static BOOL
|
||||
ME_StreamOutPrint(ME_TextEditor *editor, char *format, ...)
|
||||
{
|
||||
char string[STREAMOUT_BUFFER_SIZE]; /* This is going to be enough */
|
||||
int len;
|
||||
va_list valist;
|
||||
|
||||
va_start(valist, format);
|
||||
len = vsnprintf(string, sizeof(string), format, valist);
|
||||
va_end(valist);
|
||||
|
||||
return ME_StreamOutMove(editor, string, len);
|
||||
}
|
||||
|
||||
|
||||
static BOOL
|
||||
ME_StreamOutRTFHeader(ME_TextEditor *editor, int dwFormat)
|
||||
{
|
||||
char *cCharSet = NULL;
|
||||
UINT nCodePage;
|
||||
LANGID language;
|
||||
BOOL success;
|
||||
|
||||
if (dwFormat & SF_USECODEPAGE) {
|
||||
CPINFOEXW info;
|
||||
|
||||
switch (HIWORD(dwFormat)) {
|
||||
case CP_ACP:
|
||||
cCharSet = "ansi";
|
||||
nCodePage = GetACP();
|
||||
break;
|
||||
case CP_OEMCP:
|
||||
nCodePage = GetOEMCP();
|
||||
if (nCodePage == 437)
|
||||
cCharSet = "pc";
|
||||
else if (nCodePage == 850)
|
||||
cCharSet = "pca";
|
||||
else
|
||||
cCharSet = "ansi";
|
||||
break;
|
||||
case CP_UTF8:
|
||||
nCodePage = CP_UTF8;
|
||||
break;
|
||||
default:
|
||||
if (HIWORD(dwFormat) == CP_MACCP) {
|
||||
cCharSet = "mac";
|
||||
nCodePage = 10000; /* MacRoman */
|
||||
} else {
|
||||
cCharSet = "ansi";
|
||||
nCodePage = 1252; /* Latin-1 */
|
||||
}
|
||||
if (GetCPInfoExW(HIWORD(dwFormat), 0, &info))
|
||||
nCodePage = info.CodePage;
|
||||
}
|
||||
} else {
|
||||
cCharSet = "ansi";
|
||||
/* TODO: If the original document contained an \ansicpg value, retain it.
|
||||
* Otherwise, M$ richedit emits a codepage number determined from the
|
||||
* charset of the default font here. Anyway, this value is not used by
|
||||
* the reader... */
|
||||
nCodePage = GetACP();
|
||||
}
|
||||
if (nCodePage == CP_UTF8)
|
||||
success = ME_StreamOutPrint(editor, "{\\urtf");
|
||||
else
|
||||
success = ME_StreamOutPrint(editor, "{\\rtf1\\%s\\ansicpg%u\\uc1", cCharSet, nCodePage);
|
||||
|
||||
if (!success)
|
||||
return FALSE;
|
||||
|
||||
editor->pStream->nDefaultCodePage = nCodePage;
|
||||
|
||||
/* FIXME: This should be a document property */
|
||||
/* TODO: handle SFF_PLAINRTF */
|
||||
language = GetUserDefaultLangID();
|
||||
if (!ME_StreamOutPrint(editor, "\\deff0\\deflang%u\\deflangfe%u", language, language))
|
||||
return FALSE;
|
||||
|
||||
/* FIXME: This should be a document property */
|
||||
editor->pStream->nDefaultFont = 0;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static BOOL
|
||||
ME_StreamOutRTFFontAndColorTbl(ME_TextEditor *editor, ME_DisplayItem *pFirstRun, ME_DisplayItem *pLastRun)
|
||||
{
|
||||
ME_DisplayItem *item = pFirstRun;
|
||||
ME_FontTableItem *table = editor->pStream->fonttbl;
|
||||
int i;
|
||||
|
||||
do {
|
||||
CHARFORMAT2W *fmt = &item->member.run.style->fmt;
|
||||
COLORREF crColor;
|
||||
|
||||
if (fmt->dwMask & CFM_FACE) {
|
||||
WCHAR *face = fmt->szFaceName;
|
||||
BYTE bCharSet = (fmt->dwMask & CFM_CHARSET) ? fmt->bCharSet : DEFAULT_CHARSET;
|
||||
|
||||
for (i = 0; i < editor->pStream->nFontTblLen; i++)
|
||||
if (table[i].bCharSet == bCharSet
|
||||
&& (table[i].szFaceName == face || !lstrcmpW(table[i].szFaceName, face)))
|
||||
break;
|
||||
if (i == editor->pStream->nFontTblLen) {
|
||||
table[i].bCharSet = bCharSet;
|
||||
table[i].szFaceName = face;
|
||||
editor->pStream->nFontTblLen++;
|
||||
}
|
||||
}
|
||||
|
||||
if (fmt->dwMask & CFM_COLOR && !(fmt->dwEffects & CFE_AUTOCOLOR)) {
|
||||
crColor = fmt->crTextColor;
|
||||
for (i = 1; i < editor->pStream->nColorTblLen; i++)
|
||||
if (editor->pStream->colortbl[i] == crColor)
|
||||
break;
|
||||
if (i == editor->pStream->nColorTblLen) {
|
||||
editor->pStream->colortbl[i] = crColor;
|
||||
editor->pStream->nColorTblLen++;
|
||||
}
|
||||
}
|
||||
if (fmt->dwMask & CFM_BACKCOLOR && !(fmt->dwEffects & CFE_AUTOBACKCOLOR)) {
|
||||
crColor = fmt->crBackColor;
|
||||
for (i = 1; i < editor->pStream->nColorTblLen; i++)
|
||||
if (editor->pStream->colortbl[i] == crColor)
|
||||
break;
|
||||
if (i == editor->pStream->nColorTblLen) {
|
||||
editor->pStream->colortbl[i] = crColor;
|
||||
editor->pStream->nColorTblLen++;
|
||||
}
|
||||
}
|
||||
|
||||
if (item == pLastRun)
|
||||
break;
|
||||
item = ME_FindItemFwd(item, diRun);
|
||||
} while (item);
|
||||
|
||||
if (!ME_StreamOutPrint(editor, "{\\fonttbl"))
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < editor->pStream->nFontTblLen; i++) {
|
||||
if (table[i].bCharSet != DEFAULT_CHARSET) {
|
||||
if (!ME_StreamOutPrint(editor, "{\\f%u\\fcharset%u ", i, table[i].bCharSet))
|
||||
return FALSE;
|
||||
} else {
|
||||
if (!ME_StreamOutPrint(editor, "{\\f%u ", i))
|
||||
return FALSE;
|
||||
}
|
||||
if (!ME_StreamOutRTFText(editor, table[i].szFaceName, -1))
|
||||
return FALSE;
|
||||
if (!ME_StreamOutPrint(editor, ";}\r\n"))
|
||||
return FALSE;
|
||||
}
|
||||
if (!ME_StreamOutPrint(editor, "}"))
|
||||
return FALSE;
|
||||
|
||||
/* Output colors table if not empty */
|
||||
if (editor->pStream->nColorTblLen > 1) {
|
||||
if (!ME_StreamOutPrint(editor, "{\\colortbl;"))
|
||||
return FALSE;
|
||||
for (i = 1; i < editor->pStream->nColorTblLen; i++) {
|
||||
if (!ME_StreamOutPrint(editor, "\\red%u\\green%u\\blue%u;",
|
||||
editor->pStream->colortbl[i] & 0xFF,
|
||||
(editor->pStream->colortbl[i] >> 8) & 0xFF,
|
||||
(editor->pStream->colortbl[i] >> 16) & 0xFF))
|
||||
return FALSE;
|
||||
}
|
||||
if (!ME_StreamOutPrint(editor, "}"))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static BOOL
|
||||
ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_DisplayItem *para)
|
||||
{
|
||||
PARAFORMAT2 *fmt = para->member.para.pFmt;
|
||||
char props[STREAMOUT_BUFFER_SIZE] = "";
|
||||
int i;
|
||||
|
||||
/* TODO: Don't emit anything if the last PARAFORMAT2 is inherited */
|
||||
if (!ME_StreamOutPrint(editor, "\\pard"))
|
||||
return FALSE;
|
||||
|
||||
/* TODO: PFM_BORDER. M$ does not emit any keywords for these properties, and
|
||||
* when streaming border keywords in, PFM_BORDER is set, but wBorder field is
|
||||
* set very different from the documentation.
|
||||
* (Tested with RichEdit 5.50.25.0601) */
|
||||
|
||||
if (fmt->dwMask & PFM_ALIGNMENT) {
|
||||
switch (fmt->wAlignment) {
|
||||
case PFA_LEFT:
|
||||
/* Default alignment: not emitted */
|
||||
break;
|
||||
case PFA_RIGHT:
|
||||
strcat(props, "\\qr");
|
||||
break;
|
||||
case PFA_CENTER:
|
||||
strcat(props, "\\qc");
|
||||
break;
|
||||
case PFA_JUSTIFY:
|
||||
strcat(props, "\\qj");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fmt->dwMask & PFM_LINESPACING) {
|
||||
/* FIXME: MSDN says that the bLineSpacingRule field is controlled by the
|
||||
* PFM_SPACEAFTER flag. Is that true? I don't believe so. */
|
||||
switch (fmt->bLineSpacingRule) {
|
||||
case 0: /* Single spacing */
|
||||
strcat(props, "\\sl-240\\slmult1");
|
||||
break;
|
||||
case 1: /* 1.5 spacing */
|
||||
strcat(props, "\\sl-360\\slmult1");
|
||||
break;
|
||||
case 2: /* Double spacing */
|
||||
strcat(props, "\\sl-480\\slmult1");
|
||||
break;
|
||||
case 3:
|
||||
sprintf(props + strlen(props), "\\sl%ld\\slmult0", fmt->dyLineSpacing);
|
||||
break;
|
||||
case 4:
|
||||
sprintf(props + strlen(props), "\\sl-%ld\\slmult0", fmt->dyLineSpacing);
|
||||
break;
|
||||
case 5:
|
||||
sprintf(props + strlen(props), "\\sl-%ld\\slmult1", fmt->dyLineSpacing * 240 / 20);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fmt->dwMask & PFM_DONOTHYPHEN && fmt->wEffects & PFE_DONOTHYPHEN)
|
||||
strcat(props, "\\hyph0");
|
||||
if (fmt->dwMask & PFM_KEEP && fmt->wEffects & PFE_KEEP)
|
||||
strcat(props, "\\keep");
|
||||
if (fmt->dwMask & PFM_KEEPNEXT && fmt->wEffects & PFE_KEEPNEXT)
|
||||
strcat(props, "\\keepn");
|
||||
if (fmt->dwMask & PFM_NOLINENUMBER && fmt->wEffects & PFE_NOLINENUMBER)
|
||||
strcat(props, "\\noline");
|
||||
if (fmt->dwMask & PFM_NOWIDOWCONTROL && fmt->wEffects & PFE_NOWIDOWCONTROL)
|
||||
strcat(props, "\\nowidctlpar");
|
||||
if (fmt->dwMask & PFM_PAGEBREAKBEFORE && fmt->wEffects & PFE_PAGEBREAKBEFORE)
|
||||
strcat(props, "\\pagebb");
|
||||
if (fmt->dwMask & PFM_RTLPARA && fmt->wEffects & PFE_RTLPARA)
|
||||
strcat(props, "\\rtlpar");
|
||||
if (fmt->dwMask & PFM_SIDEBYSIDE && fmt->wEffects & PFE_SIDEBYSIDE)
|
||||
strcat(props, "\\sbys");
|
||||
if (fmt->dwMask & PFM_TABLE && fmt->dwMask & PFE_TABLE)
|
||||
strcat(props, "\\intbl");
|
||||
|
||||
if (fmt->dwMask & PFM_OFFSET)
|
||||
sprintf(props + strlen(props), "\\li%ld", fmt->dxOffset);
|
||||
if (fmt->dwMask & PFM_OFFSETINDENT || fmt->dwMask & PFM_STARTINDENT)
|
||||
sprintf(props + strlen(props), "\\fi%ld", fmt->dxStartIndent);
|
||||
if (fmt->dwMask & PFM_RIGHTINDENT)
|
||||
sprintf(props + strlen(props), "\\ri%ld", fmt->dxRightIndent);
|
||||
if (fmt->dwMask & PFM_SPACEAFTER)
|
||||
sprintf(props + strlen(props), "\\sa%ld", fmt->dySpaceAfter);
|
||||
if (fmt->dwMask & PFM_SPACEBEFORE)
|
||||
sprintf(props + strlen(props), "\\sb%ld", fmt->dySpaceBefore);
|
||||
if (fmt->dwMask & PFM_STYLE)
|
||||
sprintf(props + strlen(props), "\\s%d", fmt->sStyle);
|
||||
|
||||
if (fmt->dwMask & PFM_TABSTOPS) {
|
||||
static const char *leader[6] = { "", "\\tldot", "\\tlhyph", "\\tlul", "\\tlth", "\\tleq" };
|
||||
|
||||
for (i = 0; i < fmt->cTabCount; i++) {
|
||||
switch ((fmt->rgxTabs[i] >> 24) & 0xF) {
|
||||
case 1:
|
||||
strcat(props, "\\tqc");
|
||||
break;
|
||||
case 2:
|
||||
strcat(props, "\\tqr");
|
||||
break;
|
||||
case 3:
|
||||
strcat(props, "\\tqdec");
|
||||
break;
|
||||
case 4:
|
||||
/* Word bar tab (vertical bar). Handled below */
|
||||
break;
|
||||
}
|
||||
if (fmt->rgxTabs[i] >> 28 <= 5)
|
||||
strcat(props, leader[fmt->rgxTabs[i] >> 28]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (fmt->dwMask & PFM_SHADING) {
|
||||
static const char *style[16] = { "", "\\bgdkhoriz", "\\bgdkvert", "\\bgdkfdiag",
|
||||
"\\bgdkbdiag", "\\bgdkcross", "\\bgdkdcross",
|
||||
"\\bghoriz", "\\bgvert", "\\bgfdiag",
|
||||
"\\bgbdiag", "\\bgcross", "\\bgdcross",
|
||||
"", "", "" };
|
||||
if (fmt->wShadingWeight)
|
||||
sprintf(props + strlen(props), "\\shading%d", fmt->wShadingWeight);
|
||||
if (fmt->wShadingStyle & 0xF)
|
||||
strcat(props, style[fmt->wShadingStyle & 0xF]);
|
||||
sprintf(props + strlen(props), "\\cfpat%d\\cbpat%d",
|
||||
(fmt->wShadingStyle >> 4) & 0xF, (fmt->wShadingStyle >> 8) & 0xF);
|
||||
}
|
||||
|
||||
if (*props && !ME_StreamOutPrint(editor, props))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static BOOL
|
||||
ME_StreamOutRTFCharProps(ME_TextEditor *editor, CHARFORMAT2W *fmt)
|
||||
{
|
||||
char props[STREAMOUT_BUFFER_SIZE] = "";
|
||||
int i;
|
||||
|
||||
if (fmt->dwMask & CFM_ALLCAPS && fmt->dwEffects & CFE_ALLCAPS)
|
||||
strcat(props, "\\caps");
|
||||
if (fmt->dwMask & CFM_ANIMATION)
|
||||
sprintf(props + strlen(props), "\\animtext%u", fmt->bAnimation);
|
||||
if (fmt->dwMask & CFM_BACKCOLOR) {
|
||||
if (!(fmt->dwEffects & CFE_AUTOBACKCOLOR)) {
|
||||
for (i = 1; i < editor->pStream->nColorTblLen; i++)
|
||||
if (editor->pStream->colortbl[i] == fmt->crBackColor) {
|
||||
sprintf(props + strlen(props), "\\cb%u", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fmt->dwMask & CFM_BOLD && fmt->dwEffects & CFE_BOLD)
|
||||
strcat(props, "\\b");
|
||||
if (fmt->dwMask & CFM_COLOR) {
|
||||
if (!(fmt->dwEffects & CFE_AUTOCOLOR)) {
|
||||
for (i = 1; i < editor->pStream->nColorTblLen; i++)
|
||||
if (editor->pStream->colortbl[i] == fmt->crTextColor) {
|
||||
sprintf(props + strlen(props), "\\cf%u", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* TODO: CFM_DISABLED */
|
||||
if (fmt->dwMask & CFM_EMBOSS && fmt->dwEffects & CFE_EMBOSS)
|
||||
strcat(props, "\\embo");
|
||||
if (fmt->dwMask & CFM_HIDDEN && fmt->dwEffects & CFE_HIDDEN)
|
||||
strcat(props, "\\v");
|
||||
if (fmt->dwMask & CFM_IMPRINT && fmt->dwEffects & CFE_IMPRINT)
|
||||
strcat(props, "\\impr");
|
||||
if (fmt->dwMask & CFM_ITALIC && fmt->dwEffects & CFE_ITALIC)
|
||||
strcat(props, "\\i");
|
||||
if (fmt->dwMask & CFM_KERNING)
|
||||
sprintf(props + strlen(props), "\\kerning%u", fmt->wKerning);
|
||||
if (fmt->dwMask & CFM_LCID) {
|
||||
/* TODO: handle SFF_PLAINRTF */
|
||||
if (LOWORD(fmt->lcid) == 1024)
|
||||
strcat(props, "\\noproof\\lang1024\\langnp1024\\langfe1024\\langfenp1024");
|
||||
else
|
||||
sprintf(props + strlen(props), "\\lang%u", LOWORD(fmt->lcid));
|
||||
}
|
||||
/* CFM_LINK is not streamed out by M$ */
|
||||
if (fmt->dwMask & CFM_OFFSET) {
|
||||
if (fmt->yOffset >= 0)
|
||||
sprintf(props + strlen(props), "\\up%ld", fmt->yOffset);
|
||||
else
|
||||
sprintf(props + strlen(props), "\\dn%ld", -fmt->yOffset);
|
||||
}
|
||||
if (fmt->dwMask & CFM_OUTLINE && fmt->dwEffects & CFE_OUTLINE)
|
||||
strcat(props, "\\outl");
|
||||
if (fmt->dwMask & CFM_PROTECTED && fmt->dwEffects & CFE_PROTECTED)
|
||||
strcat(props, "\\protect");
|
||||
/* TODO: CFM_REVISED CFM_REVAUTHOR - probably using rsidtbl? */
|
||||
if (fmt->dwMask & CFM_SHADOW && fmt->dwEffects & CFE_SHADOW)
|
||||
strcat(props, "\\shad");
|
||||
if (fmt->dwMask & CFM_SIZE)
|
||||
sprintf(props + strlen(props), "\\fs%ld", fmt->yHeight / 10);
|
||||
if (fmt->dwMask & CFM_SMALLCAPS && fmt->dwEffects & CFE_SMALLCAPS)
|
||||
strcat(props, "\\scaps");
|
||||
if (fmt->dwMask & CFM_SPACING)
|
||||
sprintf(props + strlen(props), "\\expnd%u\\expndtw%u", fmt->sSpacing / 5, fmt->sSpacing);
|
||||
if (fmt->dwMask & CFM_STRIKEOUT && fmt->dwEffects & CFE_STRIKEOUT)
|
||||
strcat(props, "\\strike");
|
||||
if (fmt->dwMask & CFM_STYLE) {
|
||||
sprintf(props + strlen(props), "\\cs%u", fmt->sStyle);
|
||||
/* TODO: emit style contents here */
|
||||
}
|
||||
if (fmt->dwMask & (CFM_SUBSCRIPT | CFM_SUPERSCRIPT)) {
|
||||
if (fmt->dwEffects & CFE_SUBSCRIPT)
|
||||
strcat(props, "\\sub");
|
||||
else if (fmt->dwEffects & CFE_SUPERSCRIPT)
|
||||
strcat(props, "\\super");
|
||||
}
|
||||
if (fmt->dwMask & CFM_UNDERLINE || fmt->dwMask & CFM_UNDERLINETYPE) {
|
||||
if (fmt->dwMask & CFM_UNDERLINETYPE)
|
||||
switch (fmt->bUnderlineType) {
|
||||
case CFU_CF1UNDERLINE:
|
||||
case CFU_UNDERLINE:
|
||||
strcat(props, "\\ul");
|
||||
break;
|
||||
case CFU_UNDERLINEDOTTED:
|
||||
strcat(props, "\\uld");
|
||||
break;
|
||||
case CFU_UNDERLINEDOUBLE:
|
||||
strcat(props, "\\uldb");
|
||||
break;
|
||||
case CFU_UNDERLINEWORD:
|
||||
strcat(props, "\\ulw");
|
||||
break;
|
||||
case CFU_UNDERLINENONE:
|
||||
default:
|
||||
strcat(props, "\\ul0");
|
||||
break;
|
||||
}
|
||||
else if (fmt->dwEffects & CFE_UNDERLINE)
|
||||
strcat(props, "\\ul");
|
||||
}
|
||||
/* FIXME: How to emit CFM_WEIGHT? */
|
||||
|
||||
if (fmt->dwMask & CFM_FACE || fmt->dwMask & CFM_CHARSET) {
|
||||
WCHAR *szFaceName;
|
||||
|
||||
if (fmt->dwMask & CFM_FACE)
|
||||
szFaceName = fmt->szFaceName;
|
||||
else
|
||||
szFaceName = editor->pStream->fonttbl[0].szFaceName;
|
||||
for (i = 0; i < editor->pStream->nFontTblLen; i++) {
|
||||
if (szFaceName == editor->pStream->fonttbl[i].szFaceName
|
||||
|| !lstrcmpW(szFaceName, editor->pStream->fonttbl[i].szFaceName))
|
||||
if (!(fmt->dwMask & CFM_CHARSET)
|
||||
|| fmt->bCharSet == editor->pStream->fonttbl[i].bCharSet)
|
||||
break;
|
||||
}
|
||||
if (i < editor->pStream->nFontTblLen)
|
||||
{
|
||||
if (i != editor->pStream->nDefaultFont)
|
||||
sprintf(props + strlen(props), "\\f%u", i);
|
||||
|
||||
/* In UTF-8 mode, charsets/codepages are not used */
|
||||
if (editor->pStream->nDefaultCodePage != CP_UTF8)
|
||||
{
|
||||
if (editor->pStream->fonttbl[i].bCharSet == DEFAULT_CHARSET)
|
||||
editor->pStream->nCodePage = editor->pStream->nDefaultCodePage;
|
||||
else
|
||||
editor->pStream->nCodePage = RTFCharSetToCodePage(NULL,
|
||||
editor->pStream->fonttbl[i].bCharSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (*props)
|
||||
strcat(props, " ");
|
||||
if (!ME_StreamOutPrint(editor, props))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static BOOL
|
||||
ME_StreamOutRTFText(ME_TextEditor *editor, WCHAR *text, LONG nChars)
|
||||
{
|
||||
char buffer[STREAMOUT_BUFFER_SIZE];
|
||||
int pos = 0;
|
||||
int fit, i;
|
||||
|
||||
if (nChars == -1)
|
||||
nChars = lstrlenW(text);
|
||||
|
||||
while (nChars) {
|
||||
/* In UTF-8 mode, font charsets are not used. */
|
||||
if (editor->pStream->nDefaultCodePage == CP_UTF8) {
|
||||
/* 6 is the maximum character length in UTF-8 */
|
||||
fit = min(nChars, STREAMOUT_BUFFER_SIZE / 6);
|
||||
WideCharToMultiByte(CP_UTF8, 0, text, fit, buffer, STREAMOUT_BUFFER_SIZE,
|
||||
NULL, NULL);
|
||||
nChars -= fit;
|
||||
text += fit;
|
||||
for (i = 0; buffer[i]; i++)
|
||||
if (buffer[i] == '{' || buffer[i] == '}' || buffer[i] == '\\') {
|
||||
if (!ME_StreamOutPrint(editor, "%.*s\\", i - pos, buffer + pos))
|
||||
return FALSE;
|
||||
pos = i;
|
||||
}
|
||||
if (!pos)
|
||||
if (!ME_StreamOutPrint(editor, "%s", buffer + pos))
|
||||
return FALSE;
|
||||
pos = 0;
|
||||
} else if (*text < 128) {
|
||||
if (*text == '{' || *text == '}' || *text == '\\')
|
||||
buffer[pos++] = '\\';
|
||||
buffer[pos++] = (char)(*text++);
|
||||
nChars--;
|
||||
} else {
|
||||
BOOL unknown = FALSE;
|
||||
BYTE letter[3];
|
||||
int nBytes, i;
|
||||
|
||||
/* FIXME: In the MS docs for WideCharToMultiByte there is a big list of
|
||||
* codepages including CP_SYMBOL for which the last parameter must be set
|
||||
* to NULL for the function to succeed. But in Wine we need to care only
|
||||
* about CP_SYMBOL */
|
||||
nBytes = WideCharToMultiByte(editor->pStream->nCodePage, 0, text, 1,
|
||||
letter, 3, NULL,
|
||||
(editor->pStream->nCodePage == CP_SYMBOL) ? NULL : &unknown);
|
||||
if (unknown)
|
||||
pos += sprintf(buffer + pos, "\\u%d?", (short)*text);
|
||||
else if (*letter < 128) {
|
||||
if (*letter == '{' || *letter == '}' || *letter == '\\')
|
||||
buffer[pos++] = '\\';
|
||||
buffer[pos++] = *letter;
|
||||
} else {
|
||||
for (i = 0; i < nBytes; i++)
|
||||
pos += sprintf(buffer + pos, "\\'%02x", letter[i]);
|
||||
}
|
||||
text++;
|
||||
nChars--;
|
||||
}
|
||||
if (pos >= STREAMOUT_BUFFER_SIZE - 11) {
|
||||
if (!ME_StreamOutMove(editor, buffer, pos))
|
||||
return FALSE;
|
||||
pos = 0;
|
||||
}
|
||||
}
|
||||
return ME_StreamOutMove(editor, buffer, pos);
|
||||
}
|
||||
|
||||
|
||||
static BOOL
|
||||
ME_StreamOutRTF(ME_TextEditor *editor, int nStart, int nChars, int dwFormat)
|
||||
{
|
||||
ME_DisplayItem *p, *pEnd;
|
||||
int nOffset, nEndLen;
|
||||
ME_RunOfsFromCharOfs(editor, nStart, &p, &nOffset);
|
||||
ME_RunOfsFromCharOfs(editor, nStart+nChars, &pEnd, &nEndLen);
|
||||
|
||||
if (!ME_StreamOutRTFHeader(editor, dwFormat))
|
||||
return FALSE;
|
||||
|
||||
if (!ME_StreamOutRTFFontAndColorTbl(editor, p, pEnd))
|
||||
return FALSE;
|
||||
|
||||
/* TODO: stylesheet table */
|
||||
|
||||
/* FIXME: maybe emit something smarter for the generator? */
|
||||
if (!ME_StreamOutPrint(editor, "{\\*\\generator Wine Riched20 2.0.????;}"))
|
||||
return FALSE;
|
||||
|
||||
/* TODO: information group */
|
||||
|
||||
/* TODO: document formatting properties */
|
||||
|
||||
/* FIXME: We have only one document section */
|
||||
|
||||
/* TODO: section formatting properties */
|
||||
|
||||
if (!ME_StreamOutRTFParaProps(editor, ME_GetParagraph(p)))
|
||||
return FALSE;
|
||||
|
||||
while(1)
|
||||
{
|
||||
switch(p->type)
|
||||
{
|
||||
case diParagraph:
|
||||
if (!ME_StreamOutRTFParaProps(editor, p))
|
||||
return FALSE;
|
||||
break;
|
||||
case diRun:
|
||||
if (p == pEnd && !nEndLen)
|
||||
break;
|
||||
TRACE("flags %xh\n", p->member.run.nFlags);
|
||||
/* TODO: emit embedded objects */
|
||||
if (p->member.run.nFlags & MERF_GRAPHICS)
|
||||
FIXME("embedded objects are not handled\n");
|
||||
if (p->member.run.nFlags & MERF_ENDPARA) {
|
||||
if (!ME_StreamOutPrint(editor, "\r\n\\par"))
|
||||
return FALSE;
|
||||
nChars--;
|
||||
} else {
|
||||
int nEnd;
|
||||
|
||||
if (!ME_StreamOutPrint(editor, "{"))
|
||||
return FALSE;
|
||||
TRACE("style %p\n", p->member.run.style);
|
||||
if (!ME_StreamOutRTFCharProps(editor, &p->member.run.style->fmt))
|
||||
return FALSE;
|
||||
|
||||
nEnd = (p == pEnd) ? nEndLen : ME_StrLen(p->member.run.strText);
|
||||
if (!ME_StreamOutRTFText(editor, p->member.run.strText->szData + nOffset, nEnd - nOffset))
|
||||
return FALSE;
|
||||
nOffset = 0;
|
||||
if (!ME_StreamOutPrint(editor, "}"))
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
default: /* we missed the last item */
|
||||
assert(0);
|
||||
}
|
||||
if (p == pEnd)
|
||||
break;
|
||||
p = ME_FindItemFwd(p, diRunOrParagraphOrEnd);
|
||||
}
|
||||
if (!ME_StreamOutPrint(editor, "}"))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static BOOL
|
||||
ME_StreamOutText(ME_TextEditor *editor, int nStart, int nChars, DWORD dwFormat)
|
||||
{
|
||||
/* FIXME: use ME_RunOfsFromCharOfs */
|
||||
ME_DisplayItem *item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart);
|
||||
int nLen;
|
||||
UINT nCodePage = CP_ACP;
|
||||
BYTE *buffer = NULL;
|
||||
int nBufLen = 0;
|
||||
BOOL success = TRUE;
|
||||
|
||||
if (!item)
|
||||
return FALSE;
|
||||
|
||||
if (dwFormat & SF_USECODEPAGE)
|
||||
nCodePage = HIWORD(dwFormat);
|
||||
|
||||
/* TODO: Handle SF_TEXTIZED */
|
||||
|
||||
while (success && nChars && item) {
|
||||
nLen = ME_StrLen(item->member.run.strText) - nStart;
|
||||
if (nLen > nChars)
|
||||
nLen = nChars;
|
||||
|
||||
if (item->member.run.nFlags & MERF_ENDPARA) {
|
||||
WCHAR szEOL[] = { '\r', '\n' };
|
||||
|
||||
if (dwFormat & SF_UNICODE)
|
||||
success = ME_StreamOutMove(editor, (BYTE *)szEOL, 4);
|
||||
else
|
||||
success = ME_StreamOutMove(editor, "\r\n", 2);
|
||||
} else {
|
||||
if (dwFormat & SF_UNICODE)
|
||||
success = ME_StreamOutMove(editor, (BYTE *)(item->member.run.strText->szData + nStart),
|
||||
sizeof(WCHAR) * nLen);
|
||||
else {
|
||||
int nSize;
|
||||
|
||||
nSize = WideCharToMultiByte(nCodePage, 0, item->member.run.strText->szData + nStart,
|
||||
nLen, NULL, 0, NULL, NULL);
|
||||
if (nSize > nBufLen) {
|
||||
if (buffer)
|
||||
FREE_OBJ(buffer);
|
||||
buffer = ALLOC_N_OBJ(BYTE, nSize);
|
||||
nBufLen = nSize;
|
||||
}
|
||||
WideCharToMultiByte(nCodePage, 0, item->member.run.strText->szData + nStart,
|
||||
nLen, buffer, nSize, NULL, NULL);
|
||||
success = ME_StreamOutMove(editor, buffer, nSize - 1);
|
||||
}
|
||||
}
|
||||
|
||||
nChars -= nLen;
|
||||
nStart = 0;
|
||||
item = ME_FindItemFwd(item, diRun);
|
||||
}
|
||||
|
||||
if (buffer)
|
||||
FREE_OBJ(buffer);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
LRESULT
|
||||
ME_StreamOut(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream)
|
||||
{
|
||||
int nStart, nTo;
|
||||
|
||||
ME_StreamOutInit(editor, stream);
|
||||
|
||||
if (dwFormat & SFF_SELECTION)
|
||||
ME_GetSelection(editor, &nStart, &nTo);
|
||||
else {
|
||||
nStart = 0;
|
||||
nTo = -1;
|
||||
}
|
||||
if (nTo == -1)
|
||||
nTo = ME_GetTextLength(editor);
|
||||
TRACE("from %d to %d\n", nStart, nTo);
|
||||
|
||||
if (dwFormat & SF_RTF || dwFormat & SF_RTFNOOBJS)
|
||||
ME_StreamOutRTF(editor, nStart, nTo - nStart, dwFormat);
|
||||
else if (dwFormat & SF_TEXT || dwFormat & SF_TEXTIZED)
|
||||
ME_StreamOutText(editor, nStart, nTo - nStart, dwFormat);
|
||||
|
||||
ME_StreamOutFlush(editor);
|
||||
return ME_StreamOutFree(editor);
|
||||
}
|
|
@ -59,6 +59,19 @@ extern "C" {
|
|||
#define CFE_AUTOBACKCOLOR 0x04000000
|
||||
#define CFE_SUBSCRIPT 0x00010000
|
||||
#define CFE_SUPERSCRIPT 0x00020000
|
||||
#define CFE_ALLCAPS CFM_ALLCAPS
|
||||
#define CFE_EMBOSS CFM_EMBOSS
|
||||
#define CFE_HIDDEN CFM_HIDDEN
|
||||
#define CFE_IMPRINT CFM_IMPRINT
|
||||
#define CFE_OUTLINE CFM_OUTLINE
|
||||
#define CFE_SHADOW CFM_SHADOW
|
||||
#define CFE_SMALLCAPS CFM_SMALLCAPS
|
||||
#define CFU_CF1UNDERLINE 0xff
|
||||
#define CFU_UNDERLINENONE 0
|
||||
#define CFU_UNDERLINE 1
|
||||
#define CFU_UNDERLINEWORD 2
|
||||
#define CFU_UNDERLINEDOUBLE 3
|
||||
#define CFU_UNDERLINEDOTTED 4
|
||||
#define IMF_FORCENONE 1
|
||||
#define IMF_FORCEENABLE 2
|
||||
#define IMF_FORCEDISABLE 4
|
||||
|
@ -453,7 +466,7 @@ typedef struct _paraformat2 {
|
|||
LONG dySpaceBefore;
|
||||
LONG dySpaceAfter;
|
||||
LONG dyLineSpacing;
|
||||
SHORT sStype;
|
||||
SHORT sStyle;
|
||||
BYTE bLineSpacingRule;
|
||||
BYTE bOutlineLevel;
|
||||
WORD wShadingWeight;
|
||||
|
|
Loading…
Reference in a new issue