mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 02:25:17 +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 \
|
string.c \
|
||||||
style.c \
|
style.c \
|
||||||
undo.c \
|
undo.c \
|
||||||
wrap.c
|
wrap.c \
|
||||||
|
writer.c
|
||||||
|
|
||||||
@MAKE_DLL_RULES@
|
@MAKE_DLL_RULES@
|
||||||
|
|
||||||
|
|
|
@ -104,15 +104,15 @@ void ME_MoveCaret(ME_TextEditor *editor)
|
||||||
{
|
{
|
||||||
row = ME_FindItemBack(tmp, diStartRow);
|
row = ME_FindItemBack(tmp, diStartRow);
|
||||||
pSizeRun = run = tmp;
|
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)) {
|
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);
|
CreateCaret(editor->hWnd, NULL, 0, pSizeRun->member.run.nAscent+pSizeRun->member.run.nDescent);
|
||||||
SetCaretPos(run->member.run.pt.x+sz.cx,
|
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 {
|
} else {
|
||||||
assert(0 == "Wrapped paragraph run without a row?");
|
assert(0 == "Wrapped paragraph run without a row?");
|
||||||
CreateCaret(editor->hWnd, NULL, 0, 10);
|
CreateCaret(editor->hWnd, NULL, 0, 10);
|
||||||
|
@ -300,12 +300,6 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
|
||||||
assert(style);
|
assert(style);
|
||||||
editor->bCaretAtEnd = FALSE;
|
editor->bCaretAtEnd = FALSE;
|
||||||
|
|
||||||
/*
|
|
||||||
if (!style)
|
|
||||||
style = ME_GetInsertStyle(editor, nCursor);
|
|
||||||
else
|
|
||||||
ME_AddRefStyle(style);
|
|
||||||
*/
|
|
||||||
ME_AddRefStyle(style);
|
ME_AddRefStyle(style);
|
||||||
|
|
||||||
/* FIXME really HERE ? */
|
/* FIXME really HERE ? */
|
||||||
|
@ -317,10 +311,30 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
|
||||||
len = lstrlenW(str);
|
len = lstrlenW(str);
|
||||||
pos = str;
|
pos = str;
|
||||||
/* FIXME this sucks - no respect for unicode (what else can be a line separator in unicode?) */
|
/* 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++;
|
pos++;
|
||||||
/* handle EOLs */
|
if (pos-str < len && *pos == '\t') { /* handle tabs */
|
||||||
if (pos-str < len) {
|
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_DisplayItem *tp, *end_run;
|
||||||
ME_Paragraph *para;
|
ME_Paragraph *para;
|
||||||
ME_Style *tmp_style;
|
ME_Style *tmp_style;
|
||||||
|
@ -404,6 +418,7 @@ BOOL ME_ArrowLeft(ME_TextEditor *editor, ME_Cursor *p)
|
||||||
}
|
}
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL ME_ArrowRight(ME_TextEditor *editor, ME_Cursor *p)
|
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;
|
editor->nUDArrowX = -1;
|
||||||
|
|
||||||
y += GetScrollPos(editor->hWnd, SB_VERT);
|
y += ME_GetYScrollPos(editor);
|
||||||
|
|
||||||
tmp_cursor = editor->pCursors[0];
|
tmp_cursor = editor->pCursors[0];
|
||||||
is_selection = ME_IsSelection(editor);
|
is_selection = ME_IsSelection(editor);
|
||||||
|
@ -568,7 +583,7 @@ void ME_MouseMove(ME_TextEditor *editor, int x, int y)
|
||||||
{
|
{
|
||||||
ME_Cursor tmp_cursor;
|
ME_Cursor tmp_cursor;
|
||||||
|
|
||||||
y += GetScrollPos(editor->hWnd, SB_VERT);
|
y += ME_GetYScrollPos(editor);
|
||||||
|
|
||||||
tmp_cursor = editor->pCursors[0];
|
tmp_cursor = editor->pCursors[0];
|
||||||
if (!ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd))
|
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);
|
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)
|
void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
|
||||||
{
|
{
|
||||||
ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diStartRow);
|
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];
|
editor->pCursors[1] = editor->pCursors[0];
|
||||||
else
|
else
|
||||||
editor->pCursors[0] = editor->pCursors[1];
|
editor->pCursors[0] = editor->pCursors[1];
|
||||||
/* FIXME optimize */
|
|
||||||
ME_MarkAllForWrapping(editor);
|
|
||||||
ME_Repaint(editor);
|
ME_Repaint(editor);
|
||||||
return TRUE;
|
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];
|
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 */
|
if (GetKeyState(VK_SHIFT)>=0) /* cancelling selection */
|
||||||
{
|
{
|
||||||
/* any selection was present ? if so, it's no more, repaint ! */
|
/* any selection was present ? if so, it's no more, repaint ! */
|
||||||
editor->pCursors[1] = editor->pCursors[0];
|
editor->pCursors[1] = editor->pCursors[0];
|
||||||
if (memcmp(pTempCursor, &old_anchor, sizeof(ME_Cursor))) {
|
if (memcmp(pTempCursor, &old_anchor, sizeof(ME_Cursor))) {
|
||||||
ME_Repaint(editor);
|
return TRUE;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
return;
|
return FALSE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!memcmp(pTempCursor, &editor->pCursors[1], sizeof(ME_Cursor))) /* starting selection */
|
if (!memcmp(pTempCursor, &editor->pCursors[1], sizeof(ME_Cursor))) /* starting selection */
|
||||||
{
|
{
|
||||||
editor->pCursors[1] = *pTempCursor;
|
editor->pCursors[1] = *pTempCursor;
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ME_Repaint(editor);
|
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)
|
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_RepaintSelection(editor, &tmp_curs);
|
||||||
ME_SendSelChange(editor);
|
ME_SendSelChange(editor);
|
||||||
return TRUE;
|
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;
|
editor->nUDArrowX = -1;
|
||||||
|
@ -914,6 +1041,7 @@ BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, int nCtrl)
|
||||||
}
|
}
|
||||||
if (ME_ArrowLeft(editor, p)) {
|
if (ME_ArrowLeft(editor, p)) {
|
||||||
editor->bCaretAtEnd = FALSE; /* FIXME or maybe not */
|
editor->bCaretAtEnd = FALSE; /* FIXME or maybe not */
|
||||||
|
ME_ClearTempStyle(editor);
|
||||||
ME_MoveCaret(editor);
|
ME_MoveCaret(editor);
|
||||||
ME_DeleteTextAtCursor(editor, nCursor, 1);
|
ME_DeleteTextAtCursor(editor, nCursor, 1);
|
||||||
ME_UpdateRepaint(editor);
|
ME_UpdateRepaint(editor);
|
||||||
|
@ -927,10 +1055,12 @@ BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, int nCtrl)
|
||||||
if (ME_IsSelection(editor))
|
if (ME_IsSelection(editor))
|
||||||
{
|
{
|
||||||
ME_DeleteSelection(editor);
|
ME_DeleteSelection(editor);
|
||||||
|
ME_ClearTempStyle(editor);
|
||||||
ME_UpdateRepaint(editor);
|
ME_UpdateRepaint(editor);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
ME_DeleteTextAtCursor(editor, nCursor, 1);
|
ME_DeleteTextAtCursor(editor, nCursor, 1);
|
||||||
|
ME_ClearTempStyle(editor);
|
||||||
ME_UpdateRepaint(editor);
|
ME_UpdateRepaint(editor);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
Messages (ANSI versions not done yet)
|
Messages (ANSI versions not done yet)
|
||||||
- EM_AUTOURLDETECT 2.0
|
- EM_AUTOURLDETECT 2.0
|
||||||
- EM_CANPASTE
|
+ EM_CANPASTE
|
||||||
+ EM_CANREDO 2.0
|
+ EM_CANREDO 2.0
|
||||||
+ EM_CANUNDO
|
+ EM_CANUNDO
|
||||||
- EM_CHARFROMPOS
|
- EM_CHARFROMPOS
|
||||||
|
@ -73,7 +73,7 @@
|
||||||
- EM_LINESCROLL
|
- EM_LINESCROLL
|
||||||
- EM_PASTESPECIAL
|
- EM_PASTESPECIAL
|
||||||
- EM_POSFROMCHARS
|
- EM_POSFROMCHARS
|
||||||
- EM_REDO 2.0
|
+ EM_REDO 2.0
|
||||||
- EM_REQUESTRESIZE
|
- EM_REQUESTRESIZE
|
||||||
+ EM_REPLACESEL (proper style?) ANSI&Unicode
|
+ EM_REPLACESEL (proper style?) ANSI&Unicode
|
||||||
- EM_SCROLL
|
- EM_SCROLL
|
||||||
|
@ -102,17 +102,17 @@
|
||||||
- EM_SETWORDBREAKPROCEX
|
- EM_SETWORDBREAKPROCEX
|
||||||
- EM_SETWORDWRAPMODE 1.0asian
|
- EM_SETWORDWRAPMODE 1.0asian
|
||||||
- EM_STOPGROUPTYPING 2.0
|
- EM_STOPGROUPTYPING 2.0
|
||||||
- EM_STREAMIN
|
+ EM_STREAMIN (can't fall back to text when the RTF isn't really RTF)
|
||||||
- EM_STREAMOUT
|
+ EM_STREAMOUT
|
||||||
- EM_UNDO
|
+ EM_UNDO
|
||||||
+ WM_CHAR
|
+ WM_CHAR
|
||||||
+ WM_CLEAR
|
+ WM_CLEAR
|
||||||
- WM_COPY (lame implementation, no RTF support)
|
+ WM_COPY
|
||||||
- WM_CUT (lame implementation, no RTF support)
|
+ WM_CUT
|
||||||
+ WM_GETDLGCODE (the current implementation is incomplete)
|
+ WM_GETDLGCODE (the current implementation is incomplete)
|
||||||
+ WM_GETTEXT (ANSI&Unicode)
|
+ WM_GETTEXT (ANSI&Unicode)
|
||||||
+ WM_GETTEXTLENGTH (ANSI version sucks)
|
+ WM_GETTEXTLENGTH (ANSI version sucks)
|
||||||
- WM_PASTE
|
+ WM_PASTE
|
||||||
- WM_SETFONT
|
- WM_SETFONT
|
||||||
+ WM_SETTEXT (resets undo stack !) (proper style?) ANSI&Unicode
|
+ WM_SETTEXT (resets undo stack !) (proper style?) ANSI&Unicode
|
||||||
- WM_STYLECHANGING
|
- WM_STYLECHANGING
|
||||||
|
@ -166,30 +166,25 @@
|
||||||
/*
|
/*
|
||||||
* RICHED20 TODO (incomplete):
|
* RICHED20 TODO (incomplete):
|
||||||
*
|
*
|
||||||
* - font caching
|
* - messages/styles/notifications listed above
|
||||||
|
* - Undo coalescing
|
||||||
* - add remaining CHARFORMAT/PARAFORMAT fields
|
* - add remaining CHARFORMAT/PARAFORMAT fields
|
||||||
* - right/center align should strip spaces from the beginning
|
* - right/center align should strip spaces from the beginning
|
||||||
* - more advanced navigation (Ctrl-arrows, PageUp/PageDn)
|
* - more advanced navigation (Ctrl-arrows)
|
||||||
* - tabs
|
* - tabs
|
||||||
* - pictures (not just smiling faces that lack API support ;-) )
|
* - pictures/OLE objects (not just smiling faces that lack API support ;-) )
|
||||||
* - OLE objects
|
* - COM interface (looks like a major pain in the TODO list)
|
||||||
* - calculate heights of pictures (half-done)
|
* - calculate heights of pictures (half-done)
|
||||||
* - EM_STREAMIN/EM_STREAMOUT
|
|
||||||
* - horizontal scrolling (not even started)
|
* - horizontal scrolling (not even started)
|
||||||
* - fix scrollbars and refresh (it sucks bigtime)
|
|
||||||
* - hysteresis during wrapping (related to scrollbars appearing/disappearing)
|
* - hysteresis during wrapping (related to scrollbars appearing/disappearing)
|
||||||
* - should remember maximum row width for wrap hysteresis
|
|
||||||
* - find/replace
|
* - find/replace
|
||||||
* - how to implement EM_FORMATRANGE and EM_DISPLAYBAND ? (Mission Impossible)
|
* - how to implement EM_FORMATRANGE and EM_DISPLAYBAND ? (Mission Impossible)
|
||||||
* - italic cursor with italic fonts
|
* - italic caret with italic fonts
|
||||||
* - IME
|
* - IME
|
||||||
* - most notifications aren't sent at all (the most important ones are)
|
* - 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?)
|
* - 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)
|
* - 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)
|
* - 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:
|
* Bugs that are probably fixed, but not so easy to verify:
|
||||||
* - EN_UPDATE/EN_CHANGE are handled very incorrectly (should be OK now)
|
* - EN_UPDATE/EN_CHANGE are handled very incorrectly (should be OK now)
|
||||||
|
@ -203,11 +198,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "editor.h"
|
#include "editor.h"
|
||||||
#include <ole2.h>
|
#include "ole2.h"
|
||||||
#include <richole.h>
|
#include "richole.h"
|
||||||
#include <winreg.h>
|
#include "winreg.h"
|
||||||
#define NO_SHLWAPI_STREAM
|
#define NO_SHLWAPI_STREAM
|
||||||
#include <shlwapi.h>
|
#include "shlwapi.h"
|
||||||
|
|
||||||
#include "rtf.h"
|
#include "rtf.h"
|
||||||
|
|
||||||
|
@ -238,91 +233,388 @@ ME_TextBuffer *ME_MakeText() {
|
||||||
return buf;
|
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 wszText[STREAMIN_BUFFER_SIZE+1];
|
||||||
|
WCHAR *pText;
|
||||||
|
|
||||||
TRACE("%08lx %p\n", dwFormat, stream);
|
TRACE("%08lx %p\n", dwFormat, stream);
|
||||||
stream->dwError = 0;
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
long nDataSize = 0, nWideChars = 0;
|
long nWideChars = 0;
|
||||||
stream->dwError = stream->pfnCallback(stream->dwCookie,
|
|
||||||
(dwFormat & SF_UNICODE ? (BYTE *)wszText : buffer),
|
if (!stream->dwSize)
|
||||||
STREAMIN_BUFFER_SIZE, &nDataSize);
|
{
|
||||||
|
ME_StreamInFill(stream);
|
||||||
if (stream->dwError)
|
if (stream->editstream->dwError)
|
||||||
break;
|
break;
|
||||||
if (!nDataSize)
|
if (!stream->dwSize)
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(dwFormat & SF_UNICODE))
|
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 */
|
/* 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
|
else
|
||||||
nWideChars = nDataSize>>1;
|
{
|
||||||
ME_InsertTextFromCursor(editor, 0, wszText, nWideChars, style);
|
nWideChars = stream->dwSize >> 1;
|
||||||
if (nDataSize<STREAMIN_BUFFER_SIZE)
|
pText = (WCHAR *)stream->buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
ME_InsertTextFromCursor(editor, 0, pText, nWideChars, style);
|
||||||
|
if (stream->dwSize < STREAMIN_BUFFER_SIZE)
|
||||||
break;
|
break;
|
||||||
} while(1);
|
} while(1);
|
||||||
ME_CommitUndo(editor);
|
ME_CommitUndo(editor);
|
||||||
|
ME_Repaint(editor);
|
||||||
return 0;
|
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)
|
static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stream)
|
||||||
{
|
{
|
||||||
RTF_Info parser;
|
RTF_Info parser;
|
||||||
ME_Style *style;
|
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);
|
TRACE("%p %p\n", stream, editor->hWnd);
|
||||||
|
editor->nEventMask = 0;
|
||||||
|
|
||||||
|
ME_GetSelection(editor, &from, &to);
|
||||||
if (format & SFF_SELECTION) {
|
if (format & SFF_SELECTION) {
|
||||||
style = ME_GetSelectionInsertStyle(editor);
|
style = ME_GetSelectionInsertStyle(editor);
|
||||||
SendMessageW(editor->hWnd, WM_CLEAR, 0, 0);
|
|
||||||
|
ME_InternalDeleteText(editor, from, to-from);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
style = editor->pBuffer->pDefaultStyle;
|
style = editor->pBuffer->pDefaultStyle;
|
||||||
ME_AddRefStyle(style);
|
ME_AddRefStyle(style);
|
||||||
SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
|
SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
|
||||||
SetWindowTextA(editor->hWnd, "");
|
ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
|
||||||
|
from = to = 0;
|
||||||
ME_ClearTempStyle(editor);
|
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) {
|
if (!inStream.editstream->dwError)
|
||||||
/* 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
|
|
||||||
{
|
{
|
||||||
/* 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;
|
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 *ME_MakeEditor(HWND hWnd) {
|
||||||
ME_TextEditor *ed = ALLOC_OBJ(ME_TextEditor);
|
ME_TextEditor *ed = ALLOC_OBJ(ME_TextEditor);
|
||||||
HDC hDC;
|
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].pRun = ME_FindItemFwd(ed->pBuffer->pFirst, diRun);
|
||||||
ed->pCursors[1].nOffset = 0;
|
ed->pCursors[1].nOffset = 0;
|
||||||
ed->nLastTotalLength = ed->nTotalLength = 0;
|
ed->nLastTotalLength = ed->nTotalLength = 0;
|
||||||
ed->nScrollPos = 0;
|
|
||||||
ed->nUDArrowX = -1;
|
ed->nUDArrowX = -1;
|
||||||
ed->nSequence = 0;
|
ed->nSequence = 0;
|
||||||
ed->rgbBackColor = -1;
|
ed->rgbBackColor = -1;
|
||||||
|
@ -351,6 +642,7 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
|
||||||
ed->nUndoMode = umAddToUndo;
|
ed->nUndoMode = umAddToUndo;
|
||||||
ed->nParagraphs = 1;
|
ed->nParagraphs = 1;
|
||||||
ed->nLastSelStart = ed->nLastSelEnd = 0;
|
ed->nLastSelStart = ed->nLastSelEnd = 0;
|
||||||
|
ed->nScrollPosY = 0;
|
||||||
for (i=0; i<HFONT_CACHE_SIZE; i++)
|
for (i=0; i<HFONT_CACHE_SIZE; i++)
|
||||||
{
|
{
|
||||||
ed->pFontCache[i].nRefs = 0;
|
ed->pFontCache[i].nRefs = 0;
|
||||||
|
@ -361,6 +653,70 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
|
||||||
return ed;
|
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)
|
void ME_DestroyEditor(ME_TextEditor *editor)
|
||||||
{
|
{
|
||||||
ME_DisplayItem *pFirst = editor->pBuffer->pFirst;
|
ME_DisplayItem *pFirst = editor->pBuffer->pFirst;
|
||||||
|
@ -401,7 +757,6 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
||||||
switch(msg) {
|
switch(msg) {
|
||||||
|
|
||||||
UNSUPPORTED_MSG(EM_AUTOURLDETECT)
|
UNSUPPORTED_MSG(EM_AUTOURLDETECT)
|
||||||
UNSUPPORTED_MSG(EM_CANPASTE)
|
|
||||||
UNSUPPORTED_MSG(EM_CHARFROMPOS)
|
UNSUPPORTED_MSG(EM_CHARFROMPOS)
|
||||||
UNSUPPORTED_MSG(EM_DISPLAYBAND)
|
UNSUPPORTED_MSG(EM_DISPLAYBAND)
|
||||||
UNSUPPORTED_MSG(EM_EXLIMITTEXT)
|
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_SETUNDOLIMIT)
|
||||||
UNSUPPORTED_MSG(EM_SETWORDBREAKPROC)
|
UNSUPPORTED_MSG(EM_SETWORDBREAKPROC)
|
||||||
UNSUPPORTED_MSG(EM_SETWORDBREAKPROCEX)
|
UNSUPPORTED_MSG(EM_SETWORDBREAKPROCEX)
|
||||||
UNSUPPORTED_MSG(EM_STREAMOUT)
|
|
||||||
UNSUPPORTED_MSG(WM_SETFONT)
|
UNSUPPORTED_MSG(WM_SETFONT)
|
||||||
UNSUPPORTED_MSG(WM_PASTE)
|
|
||||||
UNSUPPORTED_MSG(WM_STYLECHANGING)
|
UNSUPPORTED_MSG(WM_STYLECHANGING)
|
||||||
UNSUPPORTED_MSG(WM_STYLECHANGED)
|
UNSUPPORTED_MSG(WM_STYLECHANGED)
|
||||||
/* UNSUPPORTED_MSG(WM_UNICHAR) FIXME missing in Wine headers */
|
/* 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:
|
case EM_STREAMIN:
|
||||||
return ME_StreamIn(editor, wParam, (EDITSTREAM*)lParam);
|
return ME_StreamIn(editor, wParam, (EDITSTREAM*)lParam);
|
||||||
|
case EM_STREAMOUT:
|
||||||
|
return ME_StreamOut(editor, wParam, (EDITSTREAM *)lParam);
|
||||||
case WM_GETDLGCODE:
|
case WM_GETDLGCODE:
|
||||||
{
|
{
|
||||||
UINT code = DLGC_WANTCHARS|DLGC_WANTARROWS;
|
UINT code = DLGC_WANTCHARS|DLGC_WANTARROWS;
|
||||||
|
@ -557,6 +912,7 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
||||||
case EM_SETCHARFORMAT:
|
case EM_SETCHARFORMAT:
|
||||||
{
|
{
|
||||||
CHARFORMAT2W buf, *p;
|
CHARFORMAT2W buf, *p;
|
||||||
|
BOOL bRepaint = TRUE;
|
||||||
p = ME_ToCF2W(&buf, (CHARFORMAT2W *)lParam);
|
p = ME_ToCF2W(&buf, (CHARFORMAT2W *)lParam);
|
||||||
if (!wParam)
|
if (!wParam)
|
||||||
ME_SetDefaultCharFormat(editor, p);
|
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");
|
FIXME("word selection not supported\n");
|
||||||
else if (wParam == SCF_ALL)
|
else if (wParam == SCF_ALL)
|
||||||
ME_SetCharFormat(editor, 0, ME_GetTextLength(editor), p);
|
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_SetSelectionCharFormat(editor, p);
|
||||||
|
}
|
||||||
ME_CommitUndo(editor);
|
ME_CommitUndo(editor);
|
||||||
ME_UpdateRepaint(editor);
|
if (bRepaint)
|
||||||
|
ME_UpdateRepaint(editor);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case EM_GETCHARFORMAT:
|
case EM_GETCHARFORMAT:
|
||||||
|
@ -583,6 +944,7 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
||||||
}
|
}
|
||||||
case EM_SETPARAFORMAT:
|
case EM_SETPARAFORMAT:
|
||||||
ME_SetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam);
|
ME_SetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam);
|
||||||
|
ME_UpdateRepaint(editor);
|
||||||
ME_CommitUndo(editor);
|
ME_CommitUndo(editor);
|
||||||
return 0;
|
return 0;
|
||||||
case EM_GETPARAFORMAT:
|
case EM_GETPARAFORMAT:
|
||||||
|
@ -635,12 +997,49 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
||||||
ME_UpdateRepaint(editor);
|
ME_UpdateRepaint(editor);
|
||||||
return 0;
|
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_CUT:
|
||||||
case WM_COPY:
|
case WM_COPY:
|
||||||
{
|
{
|
||||||
int from, to, pars;
|
int from, to, pars;
|
||||||
WCHAR *data;
|
WCHAR *data;
|
||||||
HANDLE hData;
|
HANDLE hData;
|
||||||
|
EDITSTREAM es;
|
||||||
|
ME_GlobalDestStruct gds;
|
||||||
|
|
||||||
if (!OpenClipboard(hWnd))
|
if (!OpenClipboard(hWnd))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -652,7 +1051,17 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
||||||
data = (WCHAR *)GlobalLock(hData);
|
data = (WCHAR *)GlobalLock(hData);
|
||||||
ME_GetTextW(editor, data, from, to-from, TRUE);
|
ME_GetTextW(editor, data, from, to-from, TRUE);
|
||||||
GlobalUnlock(hData);
|
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();
|
CloseClipboard();
|
||||||
if (msg == WM_CUT)
|
if (msg == WM_CUT)
|
||||||
{
|
{
|
||||||
|
@ -785,7 +1194,7 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
||||||
return 0; /* FIXME really 0 ? */
|
return 0; /* FIXME really 0 ? */
|
||||||
}
|
}
|
||||||
wstr = LOWORD(wParam);
|
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 ? */
|
/* FIXME maybe it would make sense to call EM_REPLACESEL instead ? */
|
||||||
ME_Style *style = ME_GetInsertStyle(editor, 0);
|
ME_Style *style = ME_GetInsertStyle(editor, 0);
|
||||||
ME_SaveTempStyle(editor);
|
ME_SaveTempStyle(editor);
|
||||||
|
@ -798,22 +1207,69 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
||||||
}
|
}
|
||||||
case WM_VSCROLL:
|
case WM_VSCROLL:
|
||||||
{
|
{
|
||||||
|
int nPos = editor->nScrollPosY;
|
||||||
si.cbSize = sizeof(SCROLLINFO);
|
si.cbSize = sizeof(SCROLLINFO);
|
||||||
si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE|SIF_TRACKPOS;
|
si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE|SIF_TRACKPOS;
|
||||||
GetScrollInfo(hWnd, SB_VERT, &si);
|
GetScrollInfo(hWnd, SB_VERT, &si);
|
||||||
switch(LOWORD(wParam)) {
|
switch(LOWORD(wParam)) {
|
||||||
case SB_THUMBTRACK:
|
case SB_LINEUP:
|
||||||
SetScrollPos(hWnd, SB_VERT, si.nTrackPos, FALSE);
|
nPos -= 24; /* FIXME follow the original */
|
||||||
ScrollWindow(hWnd, 0, si.nPos-si.nTrackPos, NULL, NULL);
|
if (nPos<0) nPos = 0;
|
||||||
/* InvalidateRect(hWnd, NULL, TRUE); */
|
|
||||||
UpdateWindow(hWnd);
|
|
||||||
break;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case WM_SIZE:
|
case WM_SIZE:
|
||||||
{
|
{
|
||||||
ME_MarkAllForWrapping(editor);
|
ME_MarkAllForWrapping(editor);
|
||||||
|
ME_WrapMarkedParagraphs(editor);
|
||||||
|
ME_UpdateScrollBar(editor);
|
||||||
ME_Repaint(editor);
|
ME_Repaint(editor);
|
||||||
return DefWindowProcW(hWnd, msg, wParam, lParam);
|
return DefWindowProcW(hWnd, msg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
@ -861,26 +1317,18 @@ int ME_CountParagraphsBetween(ME_TextEditor *editor, int from, int to)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, int bCRLF)
|
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;
|
int nWritten = 0;
|
||||||
|
|
||||||
while(item && item->member.para.next_para->member.para.nCharOfs <= nStart)
|
|
||||||
item = ME_FindItemFwd(item, diParagraph);
|
|
||||||
if (!item) {
|
if (!item) {
|
||||||
*buffer = L'\0';
|
*buffer = L'\0';
|
||||||
return 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);
|
assert(item);
|
||||||
|
|
||||||
nStart -= item->member.run.nCharOfs;
|
|
||||||
|
|
||||||
if (nStart)
|
if (nStart)
|
||||||
{
|
{
|
||||||
int nLen = ME_StrLen(item->member.run.strText) - nStart;
|
int nLen = ME_StrLen(item->member.run.strText) - nStart;
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
|
|
||||||
#include "editstr.h"
|
#include "editstr.h"
|
||||||
|
|
||||||
#define ALLOC_OBJ(type) (type *)HeapAlloc(me_heap, 0, sizeof(type))
|
#define ALLOC_OBJ(type) HeapAlloc(me_heap, 0, sizeof(type))
|
||||||
#define ALLOC_N_OBJ(type, count) (type *)HeapAlloc(me_heap, 0, count*sizeof(type))
|
#define ALLOC_N_OBJ(type, count) HeapAlloc(me_heap, 0, (count)*sizeof(type))
|
||||||
#define FREE_OBJ(ptr) HeapFree(me_heap, 0, ptr)
|
#define FREE_OBJ(ptr) HeapFree(me_heap, 0, ptr)
|
||||||
|
|
||||||
/* style.c */
|
/* style.c */
|
||||||
|
@ -85,6 +85,10 @@ void ME_EndToUnicode(HWND hWnd, LPVOID psz);
|
||||||
LPSTR ME_ToAnsi(HWND hWnd, LPVOID psz);
|
LPSTR ME_ToAnsi(HWND hWnd, LPVOID psz);
|
||||||
void ME_EndToAnsi(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
|
/* note: those two really return the first matching offset (starting from EOS)+1
|
||||||
* in other words, an offset of the first trailing white/black */
|
* 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_CheckCharOffsets(ME_TextEditor *editor);
|
||||||
void ME_PropagateCharOffset(ME_DisplayItem *p, int shift);
|
void ME_PropagateCharOffset(ME_DisplayItem *p, int shift);
|
||||||
void ME_GetGraphicsSize(ME_TextEditor *editor, ME_Run *run, SIZE *pSize);
|
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 */
|
/* this one accounts for 1/2 char tolerance */
|
||||||
int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run);
|
int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run);
|
||||||
int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset);
|
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);
|
int ME_FindSplitPoint(ME_Context *c, POINT *pt, ME_Run *run, int desperate);
|
||||||
void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run);
|
void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run);
|
||||||
ME_DisplayItem *ME_SplitFurther(ME_TextEditor *editor, ME_DisplayItem *run);
|
ME_DisplayItem *ME_SplitFurther(ME_TextEditor *editor, ME_DisplayItem *run);
|
||||||
void ME_CalcRunExtent(ME_Context *c, ME_Run *run);
|
void ME_CalcRunExtent(ME_Context *c, ME_Paragraph *para, ME_Run *run);
|
||||||
SIZE ME_GetRunSize(ME_Context *c, ME_Run *run, int nLen);
|
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_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCursor);
|
||||||
void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **ppRun, int *pOfs);
|
void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **ppRun, int *pOfs);
|
||||||
int ME_CharOfsFromRunOfs(ME_TextEditor *editor, ME_DisplayItem *pRun, int nOfs);
|
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);
|
void ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars);
|
||||||
int ME_GetTextLength(ME_TextEditor *editor);
|
int ME_GetTextLength(ME_TextEditor *editor);
|
||||||
ME_Style *ME_GetSelectionInsertStyle(ME_TextEditor *editor);
|
ME_Style *ME_GetSelectionInsertStyle(ME_TextEditor *editor);
|
||||||
|
BOOL ME_UpdateSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor);
|
||||||
|
|
||||||
/* wrap.c */
|
/* wrap.c */
|
||||||
void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp);
|
void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp);
|
||||||
ME_DisplayItem *ME_MakeRow(int height, int baseline, int width);
|
ME_DisplayItem *ME_MakeRow(int height, int baseline, int width);
|
||||||
void ME_InsertRowStart(ME_WrapContext *wc, ME_DisplayItem *pEnd);
|
void ME_InsertRowStart(ME_WrapContext *wc, ME_DisplayItem *pEnd);
|
||||||
void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp);
|
void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp);
|
||||||
void ME_WrapMarkedParagraphs(ME_TextEditor *editor);
|
BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor);
|
||||||
|
|
||||||
/* para.c */
|
/* para.c */
|
||||||
ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *run);
|
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_Repaint(ME_TextEditor *editor);
|
||||||
void ME_UpdateRepaint(ME_TextEditor *editor);
|
void ME_UpdateRepaint(ME_TextEditor *editor);
|
||||||
void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph);
|
void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph);
|
||||||
void ME_UpdateScrollBar(ME_TextEditor *editor, int ypos);
|
void ME_UpdateScrollBar(ME_TextEditor *editor);
|
||||||
int ME_GetScrollPos(ME_TextEditor *editor);
|
int ME_GetYScrollPos(ME_TextEditor *editor);
|
||||||
void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun);
|
void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun);
|
||||||
COLORREF ME_GetBackColor(ME_TextEditor *editor);
|
COLORREF ME_GetBackColor(ME_TextEditor *editor);
|
||||||
|
void ME_Scroll(ME_TextEditor *editor, int cx, int cy);
|
||||||
|
|
||||||
/* richole.c */
|
/* richole.c */
|
||||||
extern LRESULT CreateIRichEditOle(LPVOID *);
|
extern LRESULT CreateIRichEditOle(LPVOID *);
|
||||||
|
@ -206,7 +212,12 @@ void ME_Undo(ME_TextEditor *editor);
|
||||||
void ME_Redo(ME_TextEditor *editor);
|
void ME_Redo(ME_TextEditor *editor);
|
||||||
void ME_EmptyUndoStack(ME_TextEditor *editor);
|
void ME_EmptyUndoStack(ME_TextEditor *editor);
|
||||||
int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, BOOL bCRLF);
|
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 int me_debug;
|
||||||
extern HANDLE me_heap;
|
extern HANDLE me_heap;
|
||||||
extern void DoWrap(ME_TextEditor *editor);
|
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
|
#define MERF_STYLEFLAGS 0x0FFF
|
||||||
/* run contains non-text content, which has its own rules for wrapping, sizing etc */
|
/* run contains non-text content, which has its own rules for wrapping, sizing etc */
|
||||||
#define MERF_GRAPHICS 1
|
#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) */
|
/* run is splittable (contains white spaces in the middle or end) */
|
||||||
#define MERF_SPLITTABLE 0x001000
|
#define MERF_SPLITTABLE 0x001000
|
||||||
|
@ -102,6 +104,11 @@ typedef enum {
|
||||||
/* the "end of paragraph" run, contains 1 character */
|
/* the "end of paragraph" run, contains 1 character */
|
||||||
#define MERF_ENDPARA 0x100000
|
#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 */
|
/* those flags are kept when the row is split */
|
||||||
#define MERF_SPLITMASK (~(0))
|
#define MERF_SPLITMASK (~(0))
|
||||||
|
|
||||||
|
@ -192,6 +199,40 @@ typedef enum {
|
||||||
umAddBackToUndo
|
umAddBackToUndo
|
||||||
} ME_UndoMode;
|
} 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
|
typedef struct tagME_FontCacheItem
|
||||||
{
|
{
|
||||||
LOGFONTW lfSpecs;
|
LOGFONTW lfSpecs;
|
||||||
|
@ -210,7 +251,6 @@ typedef struct tagME_TextEditor
|
||||||
ME_Cursor *pCursors;
|
ME_Cursor *pCursors;
|
||||||
int nCursors;
|
int nCursors;
|
||||||
SIZE sizeWindow;
|
SIZE sizeWindow;
|
||||||
int nScrollPos;
|
|
||||||
int nTotalLength, nLastTotalLength;
|
int nTotalLength, nLastTotalLength;
|
||||||
int nUDArrowX;
|
int nUDArrowX;
|
||||||
int nSequence;
|
int nSequence;
|
||||||
|
@ -224,6 +264,9 @@ typedef struct tagME_TextEditor
|
||||||
int nParagraphs;
|
int nParagraphs;
|
||||||
int nLastSelStart, nLastSelEnd;
|
int nLastSelStart, nLastSelEnd;
|
||||||
ME_FontCacheItem pFontCache[HFONT_CACHE_SIZE];
|
ME_FontCacheItem pFontCache[HFONT_CACHE_SIZE];
|
||||||
|
ME_OutStream *pStream;
|
||||||
|
BOOL bScrollX, bScrollY;
|
||||||
|
int nScrollPosY;
|
||||||
} ME_TextEditor;
|
} ME_TextEditor;
|
||||||
|
|
||||||
typedef struct tagME_Context
|
typedef struct tagME_Context
|
||||||
|
|
|
@ -28,14 +28,16 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpda
|
||||||
int yoffset;
|
int yoffset;
|
||||||
|
|
||||||
editor->nSequence++;
|
editor->nSequence++;
|
||||||
yoffset = GetScrollPos(editor->hWnd, SB_VERT);
|
yoffset = ME_GetYScrollPos(editor);
|
||||||
ME_InitContext(&c, editor, hDC);
|
ME_InitContext(&c, editor, hDC);
|
||||||
SetBkMode(hDC, TRANSPARENT);
|
SetBkMode(hDC, TRANSPARENT);
|
||||||
ME_MoveCaret(editor);
|
ME_MoveCaret(editor);
|
||||||
item = editor->pBuffer->pFirst->next;
|
item = editor->pBuffer->pFirst->next;
|
||||||
c.pt.y -= yoffset;
|
c.pt.y -= yoffset;
|
||||||
while(item != editor->pBuffer->pLast) {
|
while(item != editor->pBuffer->pLast) {
|
||||||
|
int ye;
|
||||||
assert(item->type == diParagraph);
|
assert(item->type == diParagraph);
|
||||||
|
ye = c.pt.y + item->member.para.nHeight;
|
||||||
if (!bOnlyNew || (item->member.para.nFlags & MEPF_REPAINT))
|
if (!bOnlyNew || (item->member.para.nFlags & MEPF_REPAINT))
|
||||||
{
|
{
|
||||||
BOOL bPaint = (rcUpdate == NULL);
|
BOOL bPaint = (rcUpdate == NULL);
|
||||||
|
@ -45,10 +47,11 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpda
|
||||||
if (bPaint)
|
if (bPaint)
|
||||||
{
|
{
|
||||||
ME_DrawParagraph(&c, item);
|
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;
|
item = item->member.para.next_para;
|
||||||
}
|
}
|
||||||
if (c.pt.y<c.rcView.bottom) {
|
if (c.pt.y<c.rcView.bottom) {
|
||||||
|
@ -146,18 +149,21 @@ void ME_Repaint(ME_TextEditor *editor)
|
||||||
ME_DisplayItem *pRun = NULL;
|
ME_DisplayItem *pRun = NULL;
|
||||||
int nOffset = -1;
|
int nOffset = -1;
|
||||||
HDC hDC;
|
HDC hDC;
|
||||||
|
|
||||||
int nCharOfs = ME_CharOfsFromRunOfs(editor, pCursor->pRun, pCursor->nOffset);
|
int nCharOfs = ME_CharOfsFromRunOfs(editor, pCursor->pRun, pCursor->nOffset);
|
||||||
|
|
||||||
ME_RunOfsFromCharOfs(editor, nCharOfs, &pRun, &nOffset);
|
ME_RunOfsFromCharOfs(editor, nCharOfs, &pRun, &nOffset);
|
||||||
assert(pRun == pCursor->pRun);
|
assert(pRun == pCursor->pRun);
|
||||||
assert(nOffset == pCursor->nOffset);
|
assert(nOffset == pCursor->nOffset);
|
||||||
ME_MarkSelectionForRepaint(editor);
|
ME_MarkSelectionForRepaint(editor);
|
||||||
ME_WrapMarkedParagraphs(editor);
|
if (ME_WrapMarkedParagraphs(editor)) {
|
||||||
|
ME_UpdateScrollBar(editor);
|
||||||
|
}
|
||||||
hDC = GetDC(editor->hWnd);
|
hDC = GetDC(editor->hWnd);
|
||||||
ME_HideCaret(editor);
|
ME_HideCaret(editor);
|
||||||
ME_PaintContent(editor, hDC, TRUE, NULL);
|
ME_PaintContent(editor, hDC, TRUE, NULL);
|
||||||
ReleaseDC(editor->hWnd, hDC);
|
ReleaseDC(editor->hWnd, hDC);
|
||||||
ME_ShowCaret(editor);
|
ME_ShowCaret(editor);
|
||||||
|
ME_EnsureVisible(editor, pCursor->pRun);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ME_UpdateRepaint(ME_TextEditor *editor)
|
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;
|
ME_Run *run = &rundi->member.run;
|
||||||
int runofs = run->nCharOfs+para->nCharOfs;
|
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) {
|
if (run->nFlags & MERF_GRAPHICS) {
|
||||||
int blfrom, blto;
|
int blfrom, blto;
|
||||||
ME_GetSelection(c->editor, &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);
|
visible = RectVisible(c->hDC, &rcPara);
|
||||||
if (visible) {
|
if (visible) {
|
||||||
HBRUSH hbr;
|
HBRUSH hbr;
|
||||||
|
hbr = CreateSolidBrush(ME_GetBackColor(c->editor));
|
||||||
/* left margin */
|
/* left margin */
|
||||||
rc.left = c->rcView.left;
|
rc.left = c->rcView.left;
|
||||||
rc.right = c->rcView.left+nMargWidth;
|
rc.right = c->rcView.left+nMargWidth;
|
||||||
rc.top = y;
|
rc.top = y;
|
||||||
rc.bottom = y+p->member.row.nHeight;
|
rc.bottom = y+p->member.row.nHeight;
|
||||||
FillRect(c->hDC, &rc, c->hbrMargin);
|
FillRect(c->hDC, &rc, hbr/* c->hbrMargin */);
|
||||||
/* right margin */
|
/* right margin */
|
||||||
rc.left = xe;
|
rc.left = xe;
|
||||||
rc.right = c->rcView.right;
|
rc.right = c->rcView.right;
|
||||||
FillRect(c->hDC, &rc, c->hbrMargin);
|
FillRect(c->hDC, &rc, hbr/* c->hbrMargin */);
|
||||||
rc.left = c->rcView.left+para->nLeftMargin;
|
rc.left = c->rcView.left+nMargWidth;
|
||||||
rc.right = xe;
|
rc.right = xe;
|
||||||
hbr = CreateSolidBrush(ME_GetBackColor(c->editor));
|
|
||||||
FillRect(c->hDC, &rc, hbr);
|
FillRect(c->hDC, &rc, hbr);
|
||||||
DeleteObject(hbr);
|
DeleteObject(hbr);
|
||||||
}
|
}
|
||||||
|
@ -369,62 +378,103 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
|
||||||
SetTextAlign(c->hDC, align);
|
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;
|
SCROLLINFO si;
|
||||||
HWND hWnd = editor->hWnd;
|
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) {
|
si.cbSize = sizeof(SCROLLINFO);
|
||||||
EnableScrollBar(hWnd, SB_VERT, ESB_ENABLE_BOTH);
|
si.fMask = SIF_POS;
|
||||||
SetScrollRange(hWnd, SB_VERT, 0, overflow, FALSE);
|
GetScrollInfo(hWnd, SB_VERT, &si);
|
||||||
SetScrollPos(hWnd, SB_VERT, ypos, TRUE);
|
si.nPos = editor->nScrollPosY -= cy;
|
||||||
} else {
|
SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
|
||||||
EnableScrollBar(hWnd, SB_VERT, ESB_DISABLE_BOTH);
|
if (abs(cy) > editor->sizeWindow.cy)
|
||||||
SetScrollRange(hWnd, SB_VERT, 0, 0, FALSE);
|
InvalidateRect(editor->hWnd, NULL, TRUE);
|
||||||
SetScrollPos(hWnd, SB_VERT, 0, TRUE);
|
else
|
||||||
}
|
ScrollWindowEx(hWnd, cx, cy, NULL, NULL, NULL, NULL, SW_ERASE|SW_INVALIDATE);
|
||||||
if (ypos != si.nPos)
|
}
|
||||||
|
|
||||||
|
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);
|
si.fMask = SIF_RANGE | SIF_PAGE;
|
||||||
ScrollWindow(hWnd, 0, si.nPos - ypos, NULL, NULL);
|
si.nMin = 0;
|
||||||
UpdateWindow(hWnd);
|
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)
|
void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun)
|
||||||
{
|
{
|
||||||
ME_DisplayItem *pRow = ME_FindItemBack(pRun, diStartRow);
|
ME_DisplayItem *pRow = ME_FindItemBack(pRun, diStartRow);
|
||||||
ME_DisplayItem *pPara = ME_FindItemBack(pRun, diParagraph);
|
ME_DisplayItem *pPara = ME_FindItemBack(pRun, diParagraph);
|
||||||
int y, yrel, yheight;
|
int y, yrel, yheight, yold;
|
||||||
|
HWND hWnd = editor->hWnd;
|
||||||
|
|
||||||
assert(pRow);
|
assert(pRow);
|
||||||
assert(pPara);
|
assert(pPara);
|
||||||
|
|
||||||
y = pPara->member.para.nYPos+pRow->member.row.nYPos;
|
y = pPara->member.para.nYPos+pRow->member.row.nYPos;
|
||||||
yheight = pRow->member.row.nHeight;
|
yheight = pRow->member.row.nHeight;
|
||||||
yrel = y - ME_GetScrollPos(editor);
|
yold = ME_GetYScrollPos(editor);
|
||||||
if (yrel < 0)
|
yrel = y - yold;
|
||||||
ME_UpdateScrollBar(editor, y);
|
if (yrel < 0) {
|
||||||
else if (yrel + yheight > editor->sizeWindow.cy)
|
editor->nScrollPosY = y;
|
||||||
{
|
SetScrollPos(hWnd, SB_VERT, y, TRUE);
|
||||||
ME_UpdateScrollBar(editor, y + yheight - editor->sizeWindow.cy);
|
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));
|
ZeroMemory(&fmt, sizeof(fmt));
|
||||||
fmt.cbSize = 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));
|
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)
|
if (pFmt->dwMask & PFM_ALIGNMENT)
|
||||||
para->member.para.pFmt->wAlignment = pFmt->wAlignment;
|
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) */
|
/* FIXME to be continued (indents, bulleting and such) */
|
||||||
|
|
||||||
|
@ -310,7 +322,6 @@ void ME_SetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt)
|
||||||
break;
|
break;
|
||||||
para = para->member.para.next_para;
|
para = para->member.para.next_para;
|
||||||
} while(1);
|
} while(1);
|
||||||
ME_Repaint(editor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ME_GetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *pFmt)
|
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));
|
ZeroMemory(&tmp, sizeof(tmp));
|
||||||
tmp.cbSize = sizeof(tmp);
|
tmp.cbSize = sizeof(tmp);
|
||||||
ME_GetParaFormat(editor, para, &tmp);
|
ME_GetParaFormat(editor, para, &tmp);
|
||||||
assert(tmp.dwMask & PFM_ALIGNMENT);
|
|
||||||
|
|
||||||
|
assert(tmp.dwMask & PFM_ALIGNMENT);
|
||||||
if (pFmt->wAlignment != tmp.wAlignment)
|
if (pFmt->wAlignment != tmp.wAlignment)
|
||||||
pFmt->dwMask &= ~PFM_ALIGNMENT;
|
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)
|
if (para == para_end)
|
||||||
return;
|
return;
|
||||||
para = para->member.para.next_para;
|
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;
|
*ppvObj = (LPVOID) This;
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
FIXME("%p: unhandled interface %s\n", This, debugstr_guid(riid) );
|
||||||
|
|
||||||
return E_NOINTERFACE;
|
return E_NOINTERFACE;
|
||||||
}
|
}
|
||||||
|
@ -215,7 +216,7 @@ static HRESULT WINAPI IRichEditOle_fnSetHostNames(IRichEditOle *me,
|
||||||
LPCSTR lpstrContainerApp, LPCSTR lpstrContainerObj)
|
LPCSTR lpstrContainerApp, LPCSTR lpstrContainerObj)
|
||||||
{
|
{
|
||||||
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
|
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
|
||||||
FIXME("stub %p\n",This);
|
FIXME("stub %p %s %s\n",This, lpstrContainerApp, lpstrContainerObj);
|
||||||
return E_NOTIMPL;
|
return E_NOTIMPL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,365 +11,6 @@
|
||||||
#include "richedit.h"
|
#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.
|
* 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)
|
# define rtfNoParam (-1000000)
|
||||||
# endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -546,7 +181,8 @@
|
||||||
# define rtfIndexRange 71
|
# define rtfIndexRange 71
|
||||||
# define rtfTOC 72
|
# define rtfTOC 72
|
||||||
# define rtfNeXTGraphic 73
|
# define rtfNeXTGraphic 73
|
||||||
# define rtfMaxDestination 74 /* highest dest + 1 */
|
# define rtfGenerator 74
|
||||||
|
# define rtfMaxDestination 75 /* highest dest + 1 */
|
||||||
|
|
||||||
# define rtfFontFamily 4
|
# define rtfFontFamily 4
|
||||||
# define rtfFFNil 0
|
# define rtfFFNil 0
|
||||||
|
@ -624,6 +260,7 @@
|
||||||
# define rtfNoWidthNonJoiner 56 /* new in 1.10 */
|
# define rtfNoWidthNonJoiner 56 /* new in 1.10 */
|
||||||
# define rtfCurHeadPict 57 /* valid? */
|
# define rtfCurHeadPict 57 /* valid? */
|
||||||
/*# define rtfCurAnnot 58*/ /* apparently not used */
|
/*# define rtfCurAnnot 58*/ /* apparently not used */
|
||||||
|
# define rtfUnicode 58 /* no better category*/
|
||||||
|
|
||||||
# define rtfStyleAttr 7
|
# define rtfStyleAttr 7
|
||||||
# define rtfAdditive 0 /* new in 1.10 */
|
# define rtfAdditive 0 /* new in 1.10 */
|
||||||
|
@ -709,6 +346,8 @@
|
||||||
# define rtfAnnotProtected 75 /* new in 1.10 */
|
# define rtfAnnotProtected 75 /* new in 1.10 */
|
||||||
# define rtfRTLDoc 76 /* new in 1.10 */
|
# define rtfRTLDoc 76 /* new in 1.10 */
|
||||||
# define rtfLTRDoc 77 /* new in 1.10 */
|
# define rtfLTRDoc 77 /* new in 1.10 */
|
||||||
|
# define rtfAnsiCodePage 78
|
||||||
|
# define rtfUTF8RTF 79
|
||||||
|
|
||||||
# define rtfSectAttr 9
|
# define rtfSectAttr 9
|
||||||
# define rtfSectDef 0
|
# define rtfSectDef 0
|
||||||
|
@ -950,6 +589,7 @@
|
||||||
# define rtfCharCharSet 33 /* new in 1.10 */
|
# define rtfCharCharSet 33 /* new in 1.10 */
|
||||||
# define rtfLanguage 34
|
# define rtfLanguage 34
|
||||||
# define rtfGray 35
|
# define rtfGray 35
|
||||||
|
# define rtfUnicodeLength 36
|
||||||
|
|
||||||
# define rtfPictAttr 13
|
# define rtfPictAttr 13
|
||||||
# define rtfMacQD 0
|
# define rtfMacQD 0
|
||||||
|
@ -1287,20 +927,6 @@
|
||||||
# define rtfLangTurkish 0x041f
|
# define rtfLangTurkish 0x041f
|
||||||
# define rtfLangUrdu 0x0420
|
# 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
|
* Style types
|
||||||
*/
|
*/
|
||||||
|
@ -1381,20 +1007,25 @@ struct RTFStyleElt
|
||||||
|
|
||||||
# define New(t) ((t *) RTFAlloc ((int) sizeof (t)))
|
# define New(t) ((t *) RTFAlloc ((int) sizeof (t)))
|
||||||
|
|
||||||
/* maximum number of character values representable in a byte */
|
/* Parser stack size */
|
||||||
|
|
||||||
# define charSetSize 256
|
|
||||||
|
|
||||||
/* charset stack size */
|
|
||||||
|
|
||||||
# define maxCSStack 10
|
|
||||||
|
|
||||||
|
# define maxStack 32
|
||||||
|
|
||||||
struct _RTF_Info;
|
struct _RTF_Info;
|
||||||
typedef struct _RTF_Info RTF_Info;
|
typedef struct _RTF_Info RTF_Info;
|
||||||
|
|
||||||
typedef void (*RTFFuncPtr) (RTF_Info *); /* generic function pointer */
|
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 {
|
struct _RTF_Info {
|
||||||
/*
|
/*
|
||||||
* Public variables (listed in rtf.h)
|
* Public variables (listed in rtf.h)
|
||||||
|
@ -1434,55 +1065,26 @@ struct _RTF_Info {
|
||||||
int prevChar;
|
int prevChar;
|
||||||
int bumpLine;
|
int bumpLine;
|
||||||
|
|
||||||
|
/* Document-wide attributes */
|
||||||
RTFFont *fontList; /* these lists MUST be */
|
RTFFont *fontList; /* these lists MUST be */
|
||||||
RTFColor *colorList; /* initialized to NULL */
|
RTFColor *colorList; /* initialized to NULL */
|
||||||
RTFStyle *styleList;
|
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 *inputName;
|
||||||
char *outputName;
|
char *outputName;
|
||||||
|
|
||||||
EDITSTREAM editstream;
|
ME_InStream *stream;
|
||||||
char InputBuffer[0x1000];
|
|
||||||
DWORD dwInputSize;
|
|
||||||
DWORD dwInputUsed;
|
|
||||||
|
|
||||||
/* edit window to output to */
|
/* edit window to output to */
|
||||||
HWND hwndEdit;
|
HWND hwndEdit;
|
||||||
|
|
||||||
/*
|
ME_TextEditor *editor;
|
||||||
* These arrays are used to map RTF input character values onto the standard
|
ME_Style *style;
|
||||||
* 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;
|
|
||||||
|
|
||||||
RTFFuncPtr ccb[rtfMaxClass]; /* class callbacks */
|
RTFFuncPtr ccb[rtfMaxClass]; /* class callbacks */
|
||||||
|
|
||||||
|
@ -1492,12 +1094,15 @@ struct _RTF_Info {
|
||||||
|
|
||||||
RTFFuncPtr panicProc;
|
RTFFuncPtr panicProc;
|
||||||
|
|
||||||
FILE *(*libFileOpen) ();
|
|
||||||
|
|
||||||
char *outMap[rtfSC_MaxChar];
|
|
||||||
|
|
||||||
DWORD dwOutputCount;
|
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 RTFInit (RTF_Info *);
|
||||||
|
void RTFDestroy(RTF_Info *info);
|
||||||
void RTFSetInputName (RTF_Info *, char *);
|
void RTFSetInputName (RTF_Info *, char *);
|
||||||
char *RTFGetInputName (RTF_Info *);
|
char *RTFGetInputName (RTF_Info *);
|
||||||
void RTFSetOutputName (RTF_Info *, char *);
|
void RTFSetOutputName (RTF_Info *, char *);
|
||||||
|
@ -1530,10 +1136,6 @@ int RTFCheckMM (RTF_Info *, int, int);
|
||||||
RTFFont *RTFGetFont (RTF_Info *, int);
|
RTFFont *RTFGetFont (RTF_Info *, int);
|
||||||
RTFColor *RTFGetColor (RTF_Info *, int);
|
RTFColor *RTFGetColor (RTF_Info *, int);
|
||||||
RTFStyle *RTFGetStyle (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 RTFCharToHex ( char);
|
||||||
int RTFHexToChar ( int );
|
int RTFHexToChar ( int );
|
||||||
void RTFSetMsgProc ( RTFFuncPtr );
|
void RTFSetMsgProc ( RTFFuncPtr );
|
||||||
|
@ -1549,22 +1151,12 @@ void RTFSetPanicProc ( RTF_Info *, RTFFuncPtr);
|
||||||
void RTFMsg (RTF_Info *, const char *fmt, ...);
|
void RTFMsg (RTF_Info *, const char *fmt, ...);
|
||||||
void RTFPanic (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 RTFFlushOutputBuffer( RTF_Info *info );
|
||||||
void RTFSetEditStream(RTF_Info *, EDITSTREAM *es);
|
void RTFSetEditStream(RTF_Info *info, ME_InStream *stream);
|
||||||
|
|
||||||
void WriterInit (RTF_Info *);
|
void WriterInit (RTF_Info *);
|
||||||
int BeginFile (RTF_Info *);
|
int BeginFile (RTF_Info *);
|
||||||
|
|
||||||
|
int RTFCharSetToCodePage(RTF_Info *info, int charset);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -26,7 +26,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit);
|
||||||
|
|
||||||
int ME_CanJoinRuns(ME_Run *run1, ME_Run *run2)
|
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;
|
return 0;
|
||||||
if (run1->style != run2->style)
|
if (run1->style != run2->style)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -91,8 +91,8 @@ void ME_CheckCharOffsets(ME_TextEditor *editor)
|
||||||
ofs = 0;
|
ofs = 0;
|
||||||
break;
|
break;
|
||||||
case diRun:
|
case diRun:
|
||||||
TRACE("run, real ofs = %d (+ofsp = %d), counted = %d, len = %d, txt = \"%s\", flags=%08x, fx&mask = %08lx\n",
|
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.nCharOfs, p->member.run.nCharOfs+ofsp, ofsp+ofs,
|
||||||
p->member.run.strText->nLen, debugstr_w(p->member.run.strText->szData),
|
p->member.run.strText->nLen, debugstr_w(p->member.run.strText->szData),
|
||||||
p->member.run.nFlags,
|
p->member.run.nFlags,
|
||||||
p->member.run.style->fmt.dwMask & p->member.run.style->fmt.dwEffects);
|
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)
|
int ME_CharOfsFromRunOfs(ME_TextEditor *editor, ME_DisplayItem *pRun, int nOfs)
|
||||||
{
|
{
|
||||||
ME_DisplayItem *pPara;
|
ME_DisplayItem *pPara;
|
||||||
|
|
||||||
assert(pRun->type == diRun);
|
assert(pRun->type == diRun);
|
||||||
assert(pRun->member.run.nCharOfs != -1);
|
assert(pRun->member.run.nCharOfs != -1);
|
||||||
|
|
||||||
pPara = ME_FindItemBack(pRun, diParagraph);
|
pPara = ME_FindItemBack(pRun, diParagraph);
|
||||||
assert(pPara);
|
assert(pPara);
|
||||||
assert(pPara->type==diParagraph);
|
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);
|
+ ME_VPosToPos(pRun->member.run.strText, nOfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **
|
||||||
{
|
{
|
||||||
ME_DisplayItem *pPara;
|
ME_DisplayItem *pPara;
|
||||||
int nParaOfs;
|
int nParaOfs;
|
||||||
|
|
||||||
pPara = editor->pBuffer->pFirst->member.para.next_para;
|
pPara = editor->pBuffer->pFirst->member.para.next_para;
|
||||||
assert(pPara);
|
assert(pPara);
|
||||||
assert(ppRun);
|
assert(ppRun);
|
||||||
|
@ -137,18 +137,18 @@ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **
|
||||||
{
|
{
|
||||||
nParaOfs = pPara->member.para.nCharOfs;
|
nParaOfs = pPara->member.para.nCharOfs;
|
||||||
assert(nCharOfs >= nParaOfs);
|
assert(nCharOfs >= nParaOfs);
|
||||||
|
|
||||||
if (nCharOfs < pPara->member.para.next_para->member.para.nCharOfs)
|
if (nCharOfs < pPara->member.para.next_para->member.para.nCharOfs)
|
||||||
{
|
{
|
||||||
*ppRun = ME_FindItemFwd(pPara, diRun);
|
*ppRun = ME_FindItemFwd(pPara, diRun);
|
||||||
assert(*ppRun);
|
assert(*ppRun);
|
||||||
while (!((*ppRun)->member.run.nFlags & MERF_ENDPARA))
|
while (!((*ppRun)->member.run.nFlags & MERF_ENDPARA))
|
||||||
{
|
{
|
||||||
ME_DisplayItem *pNext = ME_FindItemFwd(*ppRun, diRun);
|
ME_DisplayItem *pNext = ME_FindItemFwd(*ppRun, diRun);
|
||||||
assert(pNext);
|
assert(pNext);
|
||||||
assert(pNext->type == diRun);
|
assert(pNext->type == diRun);
|
||||||
if (nCharOfs < nParaOfs + pNext->member.run.nCharOfs) {
|
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);
|
nCharOfs - nParaOfs - (*ppRun)->member.run.nCharOfs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -157,12 +157,12 @@ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **
|
||||||
if (nCharOfs == nParaOfs + (*ppRun)->member.run.nCharOfs) {
|
if (nCharOfs == nParaOfs + (*ppRun)->member.run.nCharOfs) {
|
||||||
*pOfs = 0;
|
*pOfs = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pPara = pPara->member.para.next_para;
|
pPara = pPara->member.para.next_para;
|
||||||
}
|
}
|
||||||
*ppRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
|
*ppRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
|
||||||
*pOfs = 0;
|
*pOfs = 0;
|
||||||
assert((*ppRun)->member.run.nFlags & MERF_ENDPARA);
|
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);
|
assert(p->member.run.nCharOfs != -1);
|
||||||
ME_GetParagraph(p)->member.para.nFlags |= MEPF_REWRAP;
|
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++) {
|
for (i=0; i<editor->nCursors; i++) {
|
||||||
if (editor->pCursors[i].pRun == pNext) {
|
if (editor->pCursors[i].pRun == pNext) {
|
||||||
editor->pCursors[i].pRun = p;
|
editor->pCursors[i].pRun = p;
|
||||||
editor->pCursors[i].nOffset += ME_StrVLen(p->member.run.strText);
|
editor->pCursors[i].nOffset += ME_StrVLen(p->member.run.strText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ME_AppendString(p->member.run.strText, pNext->member.run.strText);
|
ME_AppendString(p->member.run.strText, pNext->member.run.strText);
|
||||||
ME_Remove(pNext);
|
ME_Remove(pNext);
|
||||||
ME_DestroyDisplayItem(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_TextEditor *editor = c->editor;
|
||||||
ME_DisplayItem *item2 = NULL;
|
ME_DisplayItem *item2 = NULL;
|
||||||
ME_Run *run, *run2;
|
ME_Run *run, *run2;
|
||||||
|
ME_Paragraph *para = &ME_GetParagraph(item)->member.para;
|
||||||
|
|
||||||
assert(item->member.run.nCharOfs != -1);
|
assert(item->member.run.nCharOfs != -1);
|
||||||
if(TRACE_ON(richedit))
|
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);
|
run->pt.x, run->pt.y);
|
||||||
|
|
||||||
item2 = ME_SplitRunSimple(editor, item, nVChar);
|
item2 = ME_SplitRunSimple(editor, item, nVChar);
|
||||||
|
|
||||||
run2 = &item2->member.run;
|
run2 = &item2->member.run;
|
||||||
|
|
||||||
ME_CalcRunExtent(c, run);
|
ME_CalcRunExtent(c, para, run);
|
||||||
ME_CalcRunExtent(c, run2);
|
ME_CalcRunExtent(c, para, run2);
|
||||||
|
|
||||||
run2->pt.x = run->pt.x+run->nWidth;
|
run2->pt.x = run->pt.x+run->nWidth;
|
||||||
run2->pt.y = run->pt.y;
|
run2->pt.y = run->pt.y;
|
||||||
|
|
||||||
if(TRACE_ON(richedit))
|
if(TRACE_ON(richedit))
|
||||||
{
|
{
|
||||||
TRACE("Before check after split\n");
|
TRACE("Before check after split\n");
|
||||||
ME_CheckCharOffsets(editor);
|
ME_CheckCharOffsets(editor);
|
||||||
TRACE("After check after split\n");
|
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(run->strText->szData), run->pt.x, run->pt.y,
|
||||||
debugstr_w(run2->strText->szData), run2->pt.x, run2->pt.y);
|
debugstr_w(run2->strText->szData), run2->pt.x, run2->pt.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
return item2;
|
return item2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* split a run starting from voffset */
|
/* split a run starting from voffset */
|
||||||
ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, int nVChar)
|
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;
|
int i;
|
||||||
assert(nVChar > 0 && nVChar < ME_StrVLen(run->strText));
|
assert(nVChar > 0 && nVChar < ME_StrVLen(run->strText));
|
||||||
assert(item->type == diRun);
|
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);
|
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);
|
ME_VSplitString(run->strText, nVChar), run->nFlags&MERF_SPLITMASK);
|
||||||
|
|
||||||
item2->member.run.nCharOfs = item->member.run.nCharOfs+
|
item2->member.run.nCharOfs = item->member.run.nCharOfs+
|
||||||
ME_VPosToPos(item->member.run.strText, nVChar);
|
ME_VPosToPos(item->member.run.strText, nVChar);
|
||||||
|
|
||||||
run2 = &item2->member.run;
|
run2 = &item2->member.run;
|
||||||
ME_InsertBefore(item->next, item2);
|
ME_InsertBefore(item->next, item2);
|
||||||
|
|
||||||
ME_UpdateRunFlags(editor, run);
|
ME_UpdateRunFlags(editor, run);
|
||||||
ME_UpdateRunFlags(editor, run2);
|
ME_UpdateRunFlags(editor, run2);
|
||||||
for (i=0; i<editor->nCursors; i++) {
|
for (i=0; i<editor->nCursors; i++) {
|
||||||
if (editor->pCursors[i].pRun == item &&
|
if (editor->pCursors[i].pRun == item &&
|
||||||
editor->pCursors[i].nOffset >= nVChar) {
|
editor->pCursors[i].nOffset >= nVChar) {
|
||||||
assert(item2->type == diRun);
|
assert(item2->type == diRun);
|
||||||
editor->pCursors[i].pRun = item2;
|
editor->pCursors[i].pRun = item2;
|
||||||
|
@ -270,18 +273,6 @@ ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, i
|
||||||
return item2;
|
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 *ME_MakeRun(ME_Style *s, ME_String *strData, int nFlags)
|
||||||
{
|
{
|
||||||
ME_DisplayItem *item = ME_MakeDI(diRun);
|
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_Cursor tmp;
|
||||||
ME_DisplayItem *pDI;
|
ME_DisplayItem *pDI;
|
||||||
ME_UndoItem *pUI;
|
ME_UndoItem *pUI;
|
||||||
|
|
||||||
assert(pItem->type == diRun || pItem->type == diUndoInsertRun);
|
assert(pItem->type == diRun || pItem->type == diUndoInsertRun);
|
||||||
|
|
||||||
pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL);
|
pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL);
|
||||||
pUI->nStart = nCharOfs;
|
if (pUI) {
|
||||||
pUI->nLen = pItem->member.run.strText->nLen;
|
pUI->nStart = nCharOfs;
|
||||||
|
pUI->nLen = pItem->member.run.strText->nLen;
|
||||||
|
}
|
||||||
ME_CursorFromCharOfs(editor, nCharOfs, &tmp);
|
ME_CursorFromCharOfs(editor, nCharOfs, &tmp);
|
||||||
if (tmp.nOffset) {
|
if (tmp.nOffset) {
|
||||||
tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, 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);
|
TRACE("Shift length:%d\n", pDI->member.run.strText->nLen);
|
||||||
ME_PropagateCharOffset(tmp.pRun, pDI->member.run.strText->nLen);
|
ME_PropagateCharOffset(tmp.pRun, pDI->member.run.strText->nLen);
|
||||||
ME_GetParagraph(tmp.pRun)->member.para.nFlags |= MEPF_REWRAP;
|
ME_GetParagraph(tmp.pRun)->member.para.nFlags |= MEPF_REWRAP;
|
||||||
|
|
||||||
return pDI;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int ME_IsWSpace(WCHAR ch)
|
return pDI;
|
||||||
{
|
|
||||||
return ch <= ' ';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run)
|
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;
|
run->nFlags |= MERF_SPLITTABLE;
|
||||||
else
|
else
|
||||||
run->nFlags &= ~MERF_SPLITTABLE;
|
run->nFlags &= ~MERF_SPLITTABLE;
|
||||||
|
|
||||||
if (!(run->nFlags & MERF_GRAPHICS)) {
|
if (!(run->nFlags & MERF_NOTEXT)) {
|
||||||
if (ME_IsWhitespaces(run->strText))
|
if (ME_IsWhitespaces(run->strText))
|
||||||
run->nFlags |= MERF_WHITESPACE | MERF_STARTWHITE | MERF_ENDWHITE;
|
run->nFlags |= MERF_WHITESPACE | MERF_STARTWHITE | MERF_ENDWHITE;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
run->nFlags &= ~MERF_WHITESPACE;
|
run->nFlags &= ~MERF_WHITESPACE;
|
||||||
|
|
||||||
if (ME_IsWSpace(ME_GetCharFwd(run->strText,0)))
|
if (ME_IsWSpace(ME_GetCharFwd(run->strText,0)))
|
||||||
run->nFlags |= MERF_STARTWHITE;
|
run->nFlags |= MERF_STARTWHITE;
|
||||||
else
|
else
|
||||||
run->nFlags &= ~MERF_STARTWHITE;
|
run->nFlags &= ~MERF_STARTWHITE;
|
||||||
|
|
||||||
if (ME_IsWSpace(ME_GetCharBack(run->strText,0)))
|
if (ME_IsWSpace(ME_GetCharBack(run->strText,0)))
|
||||||
run->nFlags |= MERF_ENDWHITE;
|
run->nFlags |= MERF_ENDWHITE;
|
||||||
else
|
else
|
||||||
|
@ -361,7 +349,7 @@ void ME_GetGraphicsSize(ME_TextEditor *editor, ME_Run *run, SIZE *pSize)
|
||||||
pSize->cy = 64;
|
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;
|
int fit = 0;
|
||||||
HGDIOBJ hOldFont;
|
HGDIOBJ hOldFont;
|
||||||
|
@ -370,6 +358,12 @@ int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run)
|
||||||
if (!run->strText->nLen)
|
if (!run->strText->nLen)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (run->nFlags & MERF_TAB)
|
||||||
|
{
|
||||||
|
if (cx < run->nWidth/2)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (run->nFlags & MERF_GRAPHICS)
|
if (run->nFlags & MERF_GRAPHICS)
|
||||||
{
|
{
|
||||||
SIZE sz;
|
SIZE sz;
|
||||||
|
@ -380,9 +374,9 @@ int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run)
|
||||||
}
|
}
|
||||||
hDC = GetDC(editor->hWnd);
|
hDC = GetDC(editor->hWnd);
|
||||||
hOldFont = ME_SelectStyleFont(editor, hDC, run->style);
|
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);
|
cx, &fit, NULL, &sz);
|
||||||
ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);
|
ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);
|
||||||
ReleaseDC(editor->hWnd, hDC);
|
ReleaseDC(editor->hWnd, hDC);
|
||||||
return fit;
|
return fit;
|
||||||
}
|
}
|
||||||
|
@ -396,6 +390,12 @@ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run)
|
||||||
if (!run->strText->nLen)
|
if (!run->strText->nLen)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (run->nFlags & MERF_TAB)
|
||||||
|
{
|
||||||
|
if (cx < run->nWidth/2)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (run->nFlags & MERF_GRAPHICS)
|
if (run->nFlags & MERF_GRAPHICS)
|
||||||
{
|
{
|
||||||
SIZE sz;
|
SIZE sz;
|
||||||
|
@ -407,19 +407,19 @@ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run)
|
||||||
|
|
||||||
hDC = GetDC(editor->hWnd);
|
hDC = GetDC(editor->hWnd);
|
||||||
hOldFont = ME_SelectStyleFont(editor, hDC, run->style);
|
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);
|
cx, &fit, NULL, &sz);
|
||||||
if (fit != run->strText->nLen)
|
if (fit != run->strText->nLen)
|
||||||
{
|
{
|
||||||
int chars = 1;
|
int chars = 1;
|
||||||
|
|
||||||
GetTextExtentPoint32W(hDC, run->strText->szData, fit, &sz2);
|
GetTextExtentPoint32W(hDC, run->strText->szData, fit, &sz2);
|
||||||
fit1 = ME_StrRelPos(run->strText, fit, &chars);
|
fit1 = ME_StrRelPos(run->strText, fit, &chars);
|
||||||
GetTextExtentPoint32W(hDC, run->strText->szData, fit1, &sz3);
|
GetTextExtentPoint32W(hDC, run->strText->szData, fit1, &sz3);
|
||||||
if (cx >= (sz2.cx+sz3.cx)/2)
|
if (cx >= (sz2.cx+sz3.cx)/2)
|
||||||
fit = fit1;
|
fit = fit1;
|
||||||
}
|
}
|
||||||
ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);
|
ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);
|
||||||
ReleaseDC(editor->hWnd, hDC);
|
ReleaseDC(editor->hWnd, hDC);
|
||||||
return fit;
|
return fit;
|
||||||
}
|
}
|
||||||
|
@ -429,7 +429,7 @@ int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset)
|
||||||
SIZE size;
|
SIZE size;
|
||||||
HDC hDC = GetDC(editor->hWnd);
|
HDC hDC = GetDC(editor->hWnd);
|
||||||
HGDIOBJ hOldFont;
|
HGDIOBJ hOldFont;
|
||||||
|
|
||||||
if (pRun->nFlags & MERF_GRAPHICS)
|
if (pRun->nFlags & MERF_GRAPHICS)
|
||||||
{
|
{
|
||||||
if (!nOffset) return 0;
|
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);
|
hOldFont = ME_SelectStyleFont(editor, hDC, pRun->style);
|
||||||
GetTextExtentPoint32W(hDC, pRun->strText->szData, nOffset, &size);
|
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);
|
ReleaseDC(editor->hWnd, hDC);
|
||||||
return size.cx;
|
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)
|
SIZE *size)
|
||||||
{
|
{
|
||||||
HDC hDC = c->hDC;
|
HDC hDC = c->hDC;
|
||||||
HGDIOBJ hOldFont;
|
HGDIOBJ hOldFont;
|
||||||
hOldFont = ME_SelectStyleFont(c->editor, hDC, s);
|
hOldFont = ME_SelectStyleFont(c->editor, hDC, s);
|
||||||
GetTextExtentPoint32W(hDC, szText, nChars, size);
|
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;
|
SIZE size;
|
||||||
int nMaxLen = ME_StrVLen(run->strText);
|
int nMaxLen = ME_StrVLen(run->strText);
|
||||||
|
|
||||||
if (nLen>nMaxLen)
|
if (nLen>nMaxLen)
|
||||||
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)
|
if (run->nFlags & MERF_GRAPHICS)
|
||||||
{
|
{
|
||||||
ME_GetGraphicsSize(c->editor, run, &size);
|
ME_GetGraphicsSize(c->editor, run, &size);
|
||||||
|
if (size.cy > *pAscent)
|
||||||
|
*pAscent = size.cy;
|
||||||
|
/* descent is unchanged */
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
ME_GetTextExtent(c, run->strText->szData, nLen, run->style, &size);
|
|
||||||
|
|
||||||
return 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);
|
int nEnd = ME_StrVLen(run->strText);
|
||||||
|
SIZE size = ME_GetRunSizeCommon(c, para, run, nEnd, &run->nAscent, &run->nDescent);
|
||||||
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);
|
|
||||||
run->nWidth = size.cx;
|
run->nWidth = size.cx;
|
||||||
run->nAscent = run->style->tm.tmAscent;
|
assert(size.cx);
|
||||||
run->nDescent = run->style->tm.tmDescent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ME_MustBeWrapped(ME_Context *c, ME_DisplayItem *para)
|
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_Cursor tmp, tmp2;
|
||||||
ME_DisplayItem *para;
|
ME_DisplayItem *para;
|
||||||
|
|
||||||
ME_CursorFromCharOfs(editor, nOfs, &tmp);
|
ME_CursorFromCharOfs(editor, nOfs, &tmp);
|
||||||
if (tmp.nOffset)
|
if (tmp.nOffset)
|
||||||
tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, 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 = ME_GetParagraph(tmp.pRun);
|
||||||
para->member.para.nFlags |= MEPF_REWRAP;
|
para->member.para.nFlags |= MEPF_REWRAP;
|
||||||
|
|
||||||
while(tmp.pRun != tmp2.pRun)
|
while(tmp.pRun != tmp2.pRun)
|
||||||
{
|
{
|
||||||
ME_UndoItem *undo = NULL;
|
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)
|
void ME_SetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *mod)
|
||||||
{
|
{
|
||||||
ME_Style *style;
|
ME_Style *style;
|
||||||
ME_UndoItem *undo;
|
ME_UndoItem *undo;
|
||||||
|
|
||||||
assert(mod->cbSize == sizeof(CHARFORMAT2W));
|
assert(mod->cbSize == sizeof(CHARFORMAT2W));
|
||||||
undo = ME_AddUndoItem(editor, diUndoSetDefaultCharFormat, NULL);
|
undo = ME_AddUndoItem(editor, diUndoSetDefaultCharFormat, NULL);
|
||||||
if (undo) {
|
if (undo) {
|
||||||
|
@ -607,10 +639,10 @@ void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nTo, CHARFORMAT2W *p
|
||||||
ME_DisplayItem *run, *run_end;
|
ME_DisplayItem *run, *run_end;
|
||||||
int nOffset, nOffset2;
|
int nOffset, nOffset2;
|
||||||
CHARFORMAT2W tmp;
|
CHARFORMAT2W tmp;
|
||||||
|
|
||||||
if (nTo>nFrom) /* selection consists of chars from nFrom up to nTo-1 */
|
if (nTo>nFrom) /* selection consists of chars from nFrom up to nTo-1 */
|
||||||
nTo--;
|
nTo--;
|
||||||
|
|
||||||
ME_RunOfsFromCharOfs(editor, nFrom, &run, &nOffset);
|
ME_RunOfsFromCharOfs(editor, nFrom, &run, &nOffset);
|
||||||
if (nFrom == nTo) /* special case - if selection is empty, take previous char's formatting */
|
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;
|
return;
|
||||||
}
|
}
|
||||||
ME_RunOfsFromCharOfs(editor, nTo, &run_end, &nOffset2);
|
ME_RunOfsFromCharOfs(editor, nTo, &run_end, &nOffset2);
|
||||||
|
|
||||||
ME_GetRunCharFormat(editor, run, pFmt);
|
ME_GetRunCharFormat(editor, run, pFmt);
|
||||||
|
|
||||||
if (run == run_end) return;
|
if (run == run_end) return;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* FIXME add more style feature comparisons */
|
/* FIXME add more style feature comparisons */
|
||||||
int nAttribs = CFM_SIZE | CFM_FACE | CFM_COLOR;
|
int nAttribs = CFM_SIZE | CFM_FACE | CFM_COLOR;
|
||||||
int nEffects = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE;
|
int nEffects = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE;
|
||||||
|
|
||||||
run = ME_FindItemFwd(run, diRun);
|
run = ME_FindItemFwd(run, diRun);
|
||||||
|
|
||||||
ZeroMemory(&tmp, sizeof(tmp));
|
ZeroMemory(&tmp, sizeof(tmp));
|
||||||
tmp.cbSize = sizeof(tmp);
|
tmp.cbSize = sizeof(tmp);
|
||||||
ME_GetRunCharFormat(editor, run, &tmp);
|
ME_GetRunCharFormat(editor, run, &tmp);
|
||||||
|
|
||||||
assert((tmp.dwMask & nAttribs) == nAttribs);
|
assert((tmp.dwMask & nAttribs) == nAttribs);
|
||||||
assert((tmp.dwMask & nEffects) == nEffects);
|
assert((tmp.dwMask & nEffects) == nEffects);
|
||||||
/* reset flags that differ */
|
/* 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 &= ~CFM_COLOR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pFmt->dwMask &= ~((pFmt->dwEffects ^ tmp.dwEffects) & nEffects);
|
pFmt->dwMask &= ~((pFmt->dwEffects ^ tmp.dwEffects) & nEffects);
|
||||||
|
|
||||||
} while(run != run_end);
|
} while(run != run_end);
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,7 @@ int ME_IsWhitespaces(ME_String *s)
|
||||||
{
|
{
|
||||||
/* FIXME multibyte */
|
/* FIXME multibyte */
|
||||||
WCHAR *pos = s->szData;
|
WCHAR *pos = s->szData;
|
||||||
while(*pos++ == ' ')
|
while(ME_IsWSpace(*pos++))
|
||||||
;
|
;
|
||||||
pos--;
|
pos--;
|
||||||
if (*pos)
|
if (*pos)
|
||||||
|
@ -123,15 +123,14 @@ int ME_IsWhitespaces(ME_String *s)
|
||||||
|
|
||||||
int ME_IsSplitable(ME_String *s)
|
int ME_IsSplitable(ME_String *s)
|
||||||
{
|
{
|
||||||
/* FIXME multibyte */
|
|
||||||
WCHAR *pos = s->szData;
|
WCHAR *pos = s->szData;
|
||||||
WCHAR ch;
|
WCHAR ch;
|
||||||
while(*pos++ == L' ')
|
while(ME_IsWSpace(*pos++))
|
||||||
;
|
;
|
||||||
pos--;
|
pos--;
|
||||||
while((ch = *pos++) != 0)
|
while((ch = *pos++) != 0)
|
||||||
{
|
{
|
||||||
if (ch == L' ')
|
if (ME_IsWSpace(ch))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -255,7 +254,7 @@ int ME_GetCharBack(ME_String *s, int nPos)
|
||||||
|
|
||||||
int ME_FindNonWhitespaceV(ME_String *s, int nVChar) {
|
int ME_FindNonWhitespaceV(ME_String *s, int nVChar) {
|
||||||
int i;
|
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;
|
return i;
|
||||||
|
@ -264,7 +263,7 @@ int ME_FindNonWhitespaceV(ME_String *s, int nVChar) {
|
||||||
/* note: returns offset of the first trailing whitespace */
|
/* note: returns offset of the first trailing whitespace */
|
||||||
int ME_ReverseFindNonWhitespaceV(ME_String *s, int nVChar) {
|
int ME_ReverseFindNonWhitespaceV(ME_String *s, int nVChar) {
|
||||||
int i;
|
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;
|
return i;
|
||||||
|
@ -273,7 +272,7 @@ int ME_ReverseFindNonWhitespaceV(ME_String *s, int nVChar) {
|
||||||
/* note: returns offset of the first trailing nonwhitespace */
|
/* note: returns offset of the first trailing nonwhitespace */
|
||||||
int ME_ReverseFindWhitespaceV(ME_String *s, int nVChar) {
|
int ME_ReverseFindWhitespaceV(ME_String *s, int nVChar) {
|
||||||
int i;
|
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;
|
return i;
|
||||||
|
|
|
@ -54,7 +54,7 @@ CHARFORMAT2W *ME_ToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from)
|
||||||
if (f->dwMask & CFM_FACE)
|
if (f->dwMask & CFM_FACE)
|
||||||
MultiByteToWideChar(0, 0, f->szFaceName, -1, to->szFaceName, sizeof(to->szFaceName));
|
MultiByteToWideChar(0, 0, f->szFaceName, -1, to->szFaceName, sizeof(to->szFaceName));
|
||||||
/* copy the rest of the 2A structure to 2W */
|
/* 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);
|
to->cbSize = sizeof(CHARFORMAT2W);
|
||||||
return to;
|
return to;
|
||||||
}
|
}
|
||||||
|
@ -124,6 +124,7 @@ ME_Style *ME_MakeStyle(CHARFORMAT2W *style) {
|
||||||
s->nSequence = -2;
|
s->nSequence = -2;
|
||||||
s->nRefs = 1;
|
s->nRefs = 1;
|
||||||
s->hFont = NULL;
|
s->hFont = NULL;
|
||||||
|
s->tm.tmAscent = -1;
|
||||||
all_refs++;
|
all_refs++;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,9 @@ void ME_EmptyUndoStack(ME_TextEditor *editor)
|
||||||
{
|
{
|
||||||
ME_DisplayItem *p, *pNext;
|
ME_DisplayItem *p, *pNext;
|
||||||
|
|
||||||
|
if (editor->nUndoMode == umIgnore)
|
||||||
|
return;
|
||||||
|
|
||||||
TRACE("Emptying undo stack\n");
|
TRACE("Emptying undo stack\n");
|
||||||
|
|
||||||
p = editor->pUndoStack;
|
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) {
|
void ME_CommitUndo(ME_TextEditor *editor) {
|
||||||
|
|
||||||
|
if (editor->nUndoMode == umIgnore)
|
||||||
|
return;
|
||||||
|
|
||||||
assert(editor->nUndoMode == umAddToUndo);
|
assert(editor->nUndoMode == umAddToUndo);
|
||||||
|
|
||||||
/* no transactions, no need to commit */
|
/* 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;
|
ME_UndoItem *pUItem = (ME_UndoItem *)pItem;
|
||||||
|
|
||||||
|
if (editor->nUndoMode == umIgnore)
|
||||||
|
return;
|
||||||
TRACE("Playing undo/redo item, id=%s\n", ME_GetDITypeName(pItem->type));
|
TRACE("Playing undo/redo item, id=%s\n", ME_GetDITypeName(pItem->type));
|
||||||
|
|
||||||
switch(pItem->type)
|
switch(pItem->type)
|
||||||
|
@ -202,6 +211,8 @@ void ME_Undo(ME_TextEditor *editor) {
|
||||||
ME_DisplayItem *p;
|
ME_DisplayItem *p;
|
||||||
ME_UndoMode nMode = editor->nUndoMode;
|
ME_UndoMode nMode = editor->nUndoMode;
|
||||||
|
|
||||||
|
if (editor->nUndoMode == umIgnore)
|
||||||
|
return;
|
||||||
assert(nMode == umAddToUndo || nMode == umIgnore);
|
assert(nMode == umAddToUndo || nMode == umIgnore);
|
||||||
|
|
||||||
/* no undo items ? */
|
/* no undo items ? */
|
||||||
|
@ -235,6 +246,8 @@ void ME_Redo(ME_TextEditor *editor) {
|
||||||
|
|
||||||
assert(nMode == umAddToUndo || nMode == umIgnore);
|
assert(nMode == umAddToUndo || nMode == umIgnore);
|
||||||
|
|
||||||
|
if (editor->nUndoMode == umIgnore)
|
||||||
|
return;
|
||||||
/* no redo items ? */
|
/* no redo items ? */
|
||||||
if (!editor->pRedoStack)
|
if (!editor->pRedoStack)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -26,16 +26,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unsolved problems:
|
* Unsolved problems:
|
||||||
*
|
*
|
||||||
* - center and right align in WordPad omits all spaces at the start, we don't
|
* - center and right align in WordPad omits all spaces at the start, we don't
|
||||||
* - objects/images are not handled yet
|
* - objects/images are not handled yet
|
||||||
* - no tabs
|
* - no tabs
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ME_DisplayItem *ME_MakeRow(int height, int baseline, int width)
|
ME_DisplayItem *ME_MakeRow(int height, int baseline, int width)
|
||||||
{
|
{
|
||||||
ME_DisplayItem *item = ME_MakeDI(diStartRow);
|
ME_DisplayItem *item = ME_MakeDI(diStartRow);
|
||||||
|
|
||||||
item->member.row.nHeight = height;
|
item->member.row.nHeight = height;
|
||||||
item->member.row.nBaseline = baseline;
|
item->member.row.nBaseline = baseline;
|
||||||
item->member.row.nWidth = width;
|
item->member.row.nWidth = width;
|
||||||
|
@ -49,7 +49,7 @@ void ME_BeginRow(ME_WrapContext *wc)
|
||||||
wc->pLastSplittableRun = NULL;
|
wc->pLastSplittableRun = NULL;
|
||||||
wc->nAvailWidth = wc->nTotalWidth - (wc->nRow ? wc->nLeftMargin : wc->nFirstMargin) - wc->nRightMargin;
|
wc->nAvailWidth = wc->nTotalWidth - (wc->nRow ? wc->nLeftMargin : wc->nFirstMargin) - wc->nRightMargin;
|
||||||
wc->pt.x = 0;
|
wc->pt.x = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ME_InsertRowStart(ME_WrapContext *wc, ME_DisplayItem *pEnd)
|
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)
|
if (wc->pRowStart)
|
||||||
ME_InsertRowStart(wc, p->next);
|
ME_InsertRowStart(wc, p->next);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
p = p->member.para.prev_para->next;
|
p = p->member.para.prev_para->next;
|
||||||
while(p) {
|
while(p) {
|
||||||
|
@ -109,15 +109,15 @@ void ME_WrapEndParagraph(ME_WrapContext *wc, ME_DisplayItem *p)
|
||||||
p = p->next;
|
p = p->next;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void ME_WrapSizeRun(ME_WrapContext *wc, ME_DisplayItem *p)
|
void ME_WrapSizeRun(ME_WrapContext *wc, ME_DisplayItem *p)
|
||||||
{
|
{
|
||||||
/* FIXME compose style (out of character and paragraph styles) here */
|
/* FIXME compose style (out of character and paragraph styles) here */
|
||||||
|
|
||||||
ME_UpdateRunFlags(wc->context->editor, &p->member.run);
|
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)
|
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)
|
while(piter != wc->pRowStart)
|
||||||
{
|
{
|
||||||
piter = ME_FindItemBack(piter, diRun);
|
piter = ME_FindItemBack(piter, diRun);
|
||||||
if (piter->member.run.nFlags & MERF_WHITESPACE)
|
if (piter->member.run.nFlags & MERF_WHITESPACE)
|
||||||
{
|
{
|
||||||
pp = piter;
|
pp = piter;
|
||||||
continue;
|
continue;
|
||||||
|
@ -167,8 +167,8 @@ ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, in
|
||||||
ME_DisplayItem *piter = p, *pp;
|
ME_DisplayItem *piter = p, *pp;
|
||||||
int i, idesp, len;
|
int i, idesp, len;
|
||||||
ME_Run *run = &p->member.run;
|
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);
|
len = ME_StrVLen(run->strText);
|
||||||
assert(len>0);
|
assert(len>0);
|
||||||
assert(i<len);
|
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));
|
TRACE("Must backtrack to split at: %s\n", debugstr_w(p->member.run.strText->szData));
|
||||||
if (wc->pLastSplittableRun)
|
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;
|
wc->pt = wc->ptLastSplittableRun;
|
||||||
return wc->pLastSplittableRun;
|
return wc->pLastSplittableRun;
|
||||||
|
@ -193,7 +193,7 @@ ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, in
|
||||||
they serve no other purpose */
|
they serve no other purpose */
|
||||||
ME_UpdateRunFlags(wc->context->editor, run);
|
ME_UpdateRunFlags(wc->context->editor, run);
|
||||||
assert((wc->pLastSplittableRun->member.run.nFlags & MERF_SPLITTABLE));
|
assert((wc->pLastSplittableRun->member.run.nFlags & MERF_SPLITTABLE));
|
||||||
|
|
||||||
piter = wc->pLastSplittableRun;
|
piter = wc->pLastSplittableRun;
|
||||||
run = &piter->member.run;
|
run = &piter->member.run;
|
||||||
len = ME_StrVLen(run->strText);
|
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);
|
i = ME_ReverseFindWhitespaceV(run->strText, len);
|
||||||
if (i == len)
|
if (i == len)
|
||||||
i = ME_ReverseFindNonWhitespaceV(run->strText, len);
|
i = ME_ReverseFindNonWhitespaceV(run->strText, len);
|
||||||
if (i) {
|
if (i) {
|
||||||
ME_DisplayItem *piter2 = ME_SplitRun(wc->context, piter, i);
|
ME_DisplayItem *piter2 = ME_SplitRun(wc->context, piter, i);
|
||||||
wc->pt = piter2->member.run.pt;
|
wc->pt = piter2->member.run.pt;
|
||||||
return piter2;
|
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 */
|
/* the run is one char, can't split it */
|
||||||
return piter;
|
return piter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
|
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;
|
ME_Run *run;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
assert(p->type == diRun);
|
assert(p->type == diRun);
|
||||||
if (!wc->pRowStart)
|
if (!wc->pRowStart)
|
||||||
wc->pRowStart = p;
|
wc->pRowStart = p;
|
||||||
ME_WrapSizeRun(wc, p);
|
|
||||||
run = &p->member.run;
|
run = &p->member.run;
|
||||||
run->pt.x = wc->pt.x;
|
run->pt.x = wc->pt.x;
|
||||||
run->pt.y = wc->pt.y;
|
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 (wc->bOverflown) /* just skipping final whitespaces */
|
||||||
{
|
{
|
||||||
if (run->nFlags & MERF_WHITESPACE) {
|
if (run->nFlags & (MERF_WHITESPACE|MERF_TAB)) {
|
||||||
p->member.run.nFlags |= MERF_SKIPPED;
|
p->member.run.nFlags |= MERF_SKIPPED;
|
||||||
/* wc->pt.x += run->nWidth; */
|
/* wc->pt.x += run->nWidth; */
|
||||||
/* skip runs consisting of only whitespaces */
|
/* skip runs consisting of only whitespaces */
|
||||||
return p->next;
|
return p->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (run->nFlags & MERF_STARTWHITE) {
|
if (run->nFlags & MERF_STARTWHITE) {
|
||||||
/* try to split the run at the first non-white char */
|
/* try to split the run at the first non-white char */
|
||||||
int black;
|
int black;
|
||||||
|
@ -274,10 +274,6 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
|
||||||
wc->bOverflown = FALSE;
|
wc->bOverflown = FALSE;
|
||||||
pp = ME_SplitRun(wc->context, p, black);
|
pp = ME_SplitRun(wc->context, p, black);
|
||||||
p->member.run.nFlags |= MERF_SKIPPED;
|
p->member.run.nFlags |= MERF_SKIPPED;
|
||||||
/*
|
|
||||||
run->pt = wc->pt;
|
|
||||||
wc->pt.x += run->nWidth;
|
|
||||||
*/
|
|
||||||
ME_InsertRowStart(wc, pp);
|
ME_InsertRowStart(wc, pp);
|
||||||
return pp;
|
return pp;
|
||||||
}
|
}
|
||||||
|
@ -290,15 +286,15 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
|
||||||
/* will current run fit? */
|
/* will current run fit? */
|
||||||
if (wc->pt.x + run->nWidth > wc->nAvailWidth)
|
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 ? */
|
/* total white run ? */
|
||||||
if (run->nFlags & MERF_WHITESPACE) {
|
if (run->nFlags & MERF_WHITESPACE) {
|
||||||
/* let the overflow logic handle it */
|
/* let the overflow logic handle it */
|
||||||
wc->bOverflown = TRUE;
|
wc->bOverflown = TRUE;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
/* graphics - we can split before */
|
/* graphics or TAB - we can split before */
|
||||||
if (run->nFlags & MERF_GRAPHICS) {
|
if (run->nFlags & (MERF_GRAPHICS|MERF_TAB)) {
|
||||||
wc->bOverflown = TRUE;
|
wc->bOverflown = TRUE;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -330,8 +326,8 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
|
||||||
ERR("failure!\n");
|
ERR("failure!\n");
|
||||||
/* not found anything - writing over margins is the only option left */
|
/* not found anything - writing over margins is the only option left */
|
||||||
}
|
}
|
||||||
if ((run->nFlags & (MERF_SPLITTABLE | MERF_STARTWHITE))
|
if ((run->nFlags & (MERF_SPLITTABLE | MERF_STARTWHITE))
|
||||||
|| ((run->nFlags & MERF_GRAPHICS) && (p != wc->pRowStart)))
|
|| ((run->nFlags & (MERF_GRAPHICS|MERF_TAB)) && (p != wc->pRowStart)))
|
||||||
{
|
{
|
||||||
wc->pLastSplittableRun = p;
|
wc->pLastSplittableRun = p;
|
||||||
wc->ptLastSplittableRun = wc->pt;
|
wc->ptLastSplittableRun = wc->pt;
|
||||||
|
@ -339,20 +335,24 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
|
||||||
wc->pt.x += run->nWidth;
|
wc->pt.x += run->nWidth;
|
||||||
return p->next;
|
return p->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) {
|
void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) {
|
||||||
ME_DisplayItem *p;
|
ME_DisplayItem *p;
|
||||||
ME_WrapContext wc;
|
ME_WrapContext wc;
|
||||||
|
int dpi = GetDeviceCaps(c->hDC, LOGPIXELSX);
|
||||||
|
|
||||||
assert(tp->type == diParagraph);
|
assert(tp->type == diParagraph);
|
||||||
if (!(tp->member.para.nFlags & MEPF_REWRAP)) {
|
if (!(tp->member.para.nFlags & MEPF_REWRAP)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ME_PrepareParagraphForWrapping(c, tp);
|
ME_PrepareParagraphForWrapping(c, tp);
|
||||||
|
|
||||||
wc.context = c;
|
wc.context = c;
|
||||||
/* wc.para_style = tp->member.para.style; */
|
/* wc.para_style = tp->member.para.style; */
|
||||||
wc.style = NULL;
|
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.nFirstMargin = tp->member.para.nFirstMargin;
|
||||||
wc.nLeftMargin = tp->member.para.nLeftMargin;
|
wc.nLeftMargin = tp->member.para.nLeftMargin;
|
||||||
wc.nRightMargin = tp->member.para.nRightMargin;
|
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.nTotalWidth = c->rcView.right - c->rcView.left;
|
||||||
wc.nAvailWidth = wc.nTotalWidth - wc.nFirstMargin - wc.nRightMargin;
|
wc.nAvailWidth = wc.nTotalWidth - wc.nFirstMargin - wc.nRightMargin;
|
||||||
wc.pRowStart = NULL;
|
wc.pRowStart = NULL;
|
||||||
|
|
||||||
ME_BeginRow(&wc);
|
ME_BeginRow(&wc);
|
||||||
for (p = tp->next; p!=tp->member.para.next_para; ) {
|
for (p = tp->next; p!=tp->member.para.next_para; ) {
|
||||||
assert(p->type != diStartRow);
|
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;
|
HWND hWnd = editor->hWnd;
|
||||||
HDC hDC = GetDC(hWnd);
|
HDC hDC = GetDC(hWnd);
|
||||||
ME_DisplayItem *item;
|
ME_DisplayItem *item;
|
||||||
ME_Context c;
|
ME_Context c;
|
||||||
|
BOOL bModified = FALSE;
|
||||||
|
|
||||||
ME_InitContext(&c, editor, hDC);
|
ME_InitContext(&c, editor, hDC);
|
||||||
c.pt.x = 0;
|
c.pt.x = 0;
|
||||||
c.pt.y = 0;
|
c.pt.y = 0;
|
||||||
item = editor->pBuffer->pFirst->next;
|
item = editor->pBuffer->pFirst->next;
|
||||||
while(item != editor->pBuffer->pLast) {
|
while(item != editor->pBuffer->pLast) {
|
||||||
BOOL bRedraw = FALSE;
|
BOOL bRedraw = FALSE;
|
||||||
|
|
||||||
assert(item->type == diParagraph);
|
assert(item->type == diParagraph);
|
||||||
if ((item->member.para.nFlags & MEPF_REWRAP)
|
if ((item->member.para.nFlags & MEPF_REWRAP)
|
||||||
|| (item->member.para.nYPos != c.pt.y))
|
|| (item->member.para.nYPos != c.pt.y))
|
||||||
bRedraw = TRUE;
|
bRedraw = TRUE;
|
||||||
item->member.para.nYPos = c.pt.y;
|
item->member.para.nYPos = c.pt.y;
|
||||||
|
|
||||||
ME_WrapTextParagraph(&c, item);
|
ME_WrapTextParagraph(&c, item);
|
||||||
|
|
||||||
if (bRedraw)
|
if (bRedraw)
|
||||||
item->member.para.nFlags |= MEPF_REPAINT;
|
item->member.para.nFlags |= MEPF_REPAINT;
|
||||||
|
|
||||||
|
bModified = bModified | bRedraw;
|
||||||
|
|
||||||
c.pt.y += item->member.para.nHeight;
|
c.pt.y += item->member.para.nHeight;
|
||||||
item = item->member.para.next_para;
|
item = item->member.para.next_para;
|
||||||
}
|
}
|
||||||
editor->sizeWindow.cx = c.rcView.right-c.rcView.left;
|
editor->sizeWindow.cx = c.rcView.right-c.rcView.left;
|
||||||
editor->sizeWindow.cy = c.rcView.bottom-c.rcView.top;
|
editor->sizeWindow.cy = c.rcView.bottom-c.rcView.top;
|
||||||
editor->nTotalLength = c.pt.y;
|
editor->nTotalLength = c.pt.y;
|
||||||
|
|
||||||
ME_DestroyContext(&c);
|
ME_DestroyContext(&c);
|
||||||
ReleaseDC(hWnd, hDC);
|
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_AUTOBACKCOLOR 0x04000000
|
||||||
#define CFE_SUBSCRIPT 0x00010000
|
#define CFE_SUBSCRIPT 0x00010000
|
||||||
#define CFE_SUPERSCRIPT 0x00020000
|
#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_FORCENONE 1
|
||||||
#define IMF_FORCEENABLE 2
|
#define IMF_FORCEENABLE 2
|
||||||
#define IMF_FORCEDISABLE 4
|
#define IMF_FORCEDISABLE 4
|
||||||
|
@ -453,7 +466,7 @@ typedef struct _paraformat2 {
|
||||||
LONG dySpaceBefore;
|
LONG dySpaceBefore;
|
||||||
LONG dySpaceAfter;
|
LONG dySpaceAfter;
|
||||||
LONG dyLineSpacing;
|
LONG dyLineSpacing;
|
||||||
SHORT sStype;
|
SHORT sStyle;
|
||||||
BYTE bLineSpacingRule;
|
BYTE bLineSpacingRule;
|
||||||
BYTE bOutlineLevel;
|
BYTE bOutlineLevel;
|
||||||
WORD wShadingWeight;
|
WORD wShadingWeight;
|
||||||
|
|
Loading…
Reference in a new issue