riched20: Add support for displaying bulleted lists.

Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
oldstable
Huw Davies 2016-10-07 10:49:35 +01:00 committed by Alexandre Julliard
parent d132009ae9
commit 8a428d52a7
6 changed files with 110 additions and 4 deletions

View File

@ -217,6 +217,8 @@ BOOL ME_SetSelectionParaFormat(ME_TextEditor *editor, const PARAFORMAT2 *pFmt) D
void ME_GetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt) DECLSPEC_HIDDEN;
void ME_MarkAllForWrapping(ME_TextEditor *editor) DECLSPEC_HIDDEN;
void ME_SetDefaultParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt) DECLSPEC_HIDDEN;
void para_num_init( ME_Context *c, ME_Paragraph *para ) DECLSPEC_HIDDEN;
void para_num_clear( struct para_num *pn ) DECLSPEC_HIDDEN;
/* paint.c */
void ME_PaintContent(ME_TextEditor *editor, HDC hDC, const RECT *rcUpdate) DECLSPEC_HIDDEN;

View File

@ -188,6 +188,14 @@ typedef struct tagME_BorderRect
ME_Border right;
} ME_BorderRect;
struct para_num
{
ME_Style *style;
ME_String *text;
INT width;
POINT pt;
};
typedef struct tagME_Paragraph
{
PARAFORMAT2 fmt;
@ -201,6 +209,7 @@ typedef struct tagME_Paragraph
POINT pt;
int nHeight, nWidth;
int nRows;
struct para_num para_num;
ME_Run *eop_run; /* ptr to the end-of-para run */
struct tagME_DisplayItem *prev_para, *next_para;
} ME_Paragraph;

View File

@ -164,6 +164,7 @@ void ME_DestroyDisplayItem(ME_DisplayItem *item)
if (item->type==diParagraph)
{
ME_DestroyString(item->member.para.text);
para_num_clear( &item->member.para.para_num );
}
if (item->type==diRun)

View File

@ -898,6 +898,25 @@ static void ME_DrawTableBorders(ME_Context *c, ME_DisplayItem *paragraph)
}
}
static void draw_para_number( ME_Context *c, ME_DisplayItem *p )
{
ME_Paragraph *para = &p->member.para;
HFONT old_font;
int x, y;
if (para->fmt.wNumbering)
{
old_font = ME_SelectStyleFont( c, para->para_num.style );
x = c->pt.x + para->para_num.pt.x;
y = c->pt.y + para->pt.y + para->para_num.pt.y;
ExtTextOutW( c->hDC, x, y, 0, NULL, para->para_num.text->szData, para->para_num.text->nLen, NULL );
ME_UnselectStyleFont( c, para->para_num.style, old_font );
}
}
static void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph)
{
int align = SetTextAlign(c->hDC, TA_BASELINE);
@ -1023,6 +1042,7 @@ static void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph)
}
ME_DrawTableBorders(c, paragraph);
draw_para_number(c, paragraph);
SetTextAlign(c->hDC, align);
}

View File

@ -128,6 +128,55 @@ static void ME_UpdateTableFlags(ME_DisplayItem *para)
para->member.para.fmt.wEffects &= ~PFE_TABLE;
}
void para_num_init( ME_Context *c, ME_Paragraph *para )
{
ME_Style *style;
CHARFORMAT2W cf;
static const WCHAR bullet_font[] = {'S','y','m','b','o','l',0};
static const WCHAR bullet_str[] = {0xb7, 0};
static const WCHAR spaceW[] = {' ', 0};
HFONT old_font;
SIZE sz;
if (para->para_num.style && para->para_num.text) return;
if (!para->para_num.style)
{
style = para->eop_run->style;
cf.cbSize = sizeof(cf);
cf.dwMask = CFM_FACE | CFM_CHARSET;
memcpy( cf.szFaceName, bullet_font, sizeof(bullet_font) );
cf.bCharSet = SYMBOL_CHARSET;
style = ME_ApplyStyle( c->editor, style, &cf );
para->para_num.style = style;
}
if (!para->para_num.text)
{
para->para_num.text = ME_MakeStringConst( bullet_str, 1 );
}
old_font = ME_SelectStyleFont( c, para->para_num.style );
GetTextExtentPointW( c->hDC, para->para_num.text->szData, para->para_num.text->nLen, &sz );
para->para_num.width = sz.cx;
GetTextExtentPointW( c->hDC, spaceW, 1, &sz );
para->para_num.width += sz.cx;
ME_UnselectStyleFont( c, para->para_num.style, old_font );
}
void para_num_clear( struct para_num *pn )
{
if (pn->style)
{
ME_ReleaseStyle( pn->style );
pn->style = NULL;
}
ME_DestroyString( pn->text );
pn->text = NULL;
}
static BOOL ME_SetParaFormat(ME_TextEditor *editor, ME_Paragraph *para, const PARAFORMAT2 *pFmt)
{
PARAFORMAT2 copy;

View File

@ -37,8 +37,10 @@ typedef struct tagME_WrapContext
{
ME_Style *style;
ME_Context *context;
int nLeftMargin, nRightMargin, nFirstMargin;
int nAvailWidth;
int nLeftMargin, nRightMargin;
int nFirstMargin; /* Offset to first line's text, always to the text itself even if a para number is present */
int nParaNumOffset; /* Offset to the para number */
int nAvailWidth; /* Width avail for text to wrap into. Does not include any para number text */
int nRow;
POINT pt;
BOOL bOverflown, bWordWrap;
@ -303,7 +305,12 @@ static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd)
BOOL bSkippingSpaces = TRUE;
int ascent = 0, descent = 0, width=0, shift = 0, align = 0;
/* wrap text */
/* Include height of para numbering label */
if (wc->nRow == 0 && para->fmt.wNumbering)
{
ascent = para->para_num.style->tm.tmAscent;
descent = para->para_num.style->tm.tmDescent;
}
for (p = pEnd->prev; p!=wc->pRowStart->prev; p = p->prev)
{
@ -367,6 +374,13 @@ static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd)
p->member.run.pt.x += row->member.row.nLMargin+shift;
}
}
if (wc->nRow == 0 && para->fmt.wNumbering)
{
para->para_num.pt.x = wc->nParaNumOffset + shift;
para->para_num.pt.y = wc->pt.y + row->member.row.nBaseline;
}
ME_InsertBefore(wc->pRowStart, row);
wc->nRow++;
wc->pt.y += row->member.row.nHeight;
@ -869,6 +883,9 @@ static void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) {
}
ME_PrepareParagraphForWrapping(c, tp);
/* Calculate paragraph numbering label */
para_num_init( c, &tp->member.para );
/* For now treating all non-password text as complex for better testing */
if (!c->editor->cPasswordMask /* &&
ScriptIsComplex( tp->member.para.text->szData, tp->member.para.text->nLen, SIC_COMPLEX ) == S_OK */)
@ -883,6 +900,7 @@ static void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) {
wc.pPara = tp;
/* wc.para_style = tp->member.para.style; */
wc.style = NULL;
wc.nParaNumOffset = 0;
if (tp->member.para.nFlags & MEPF_ROWEND) {
wc.nFirstMargin = wc.nLeftMargin = wc.nRightMargin = 0;
} else {
@ -890,8 +908,15 @@ static void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) {
if (tp->member.para.pCell) {
dxStartIndent += ME_GetTableRowEnd(tp)->member.para.fmt.dxOffset;
}
wc.nLeftMargin = ME_twips2pointsX(c, dxStartIndent + pFmt->dxOffset);
wc.nFirstMargin = ME_twips2pointsX(c, dxStartIndent);
wc.nLeftMargin = wc.nFirstMargin + ME_twips2pointsX(c, pFmt->dxOffset);
if (pFmt->wNumbering)
{
wc.nParaNumOffset = wc.nFirstMargin;
dxStartIndent = max( ME_twips2pointsX(c, pFmt->wNumberingTab),
tp->member.para.para_num.width );
wc.nFirstMargin += dxStartIndent;
}
wc.nRightMargin = ME_twips2pointsX(c, pFmt->dxRightIndent);
if (wc.nFirstMargin < 0)