wine/dlls/riched20/list.c
Huw Davies 8a428d52a7 riched20: Add support for displaying bulleted lists.
Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
2016-10-07 13:12:13 +02:00

229 lines
6.2 KiB
C

/*
* RichEdit - Basic operations on double linked lists.
*
* Copyright 2004 by Krzysztof Foltman
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "editor.h"
WINE_DEFAULT_DEBUG_CHANNEL(richedit_lists);
void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat)
{
diWhat->next = diWhere;
diWhat->prev = diWhere->prev;
diWhere->prev->next = diWhat;
diWhat->next->prev = diWhat;
}
void ME_Remove(ME_DisplayItem *diWhere)
{
ME_DisplayItem *diNext = diWhere->next;
ME_DisplayItem *diPrev = diWhere->prev;
assert(diNext);
assert(diPrev);
diPrev->next = diNext;
diNext->prev = diPrev;
}
static BOOL ME_DITypesEqual(ME_DIType type, ME_DIType nTypeOrClass)
{
switch (nTypeOrClass)
{
case diRunOrParagraph:
return type == diRun || type == diParagraph;
case diRunOrStartRow:
return type == diRun || type == diStartRow;
case diParagraphOrEnd:
return type == diTextEnd || type == diParagraph;
case diStartRowOrParagraph:
return type == diStartRow || type == diParagraph;
case diStartRowOrParagraphOrEnd:
return type == diStartRow || type == diParagraph || type == diTextEnd;
case diRunOrParagraphOrEnd:
return type == diRun || type == diParagraph || type == diTextEnd;
default:
return type == nTypeOrClass;
}
}
/* Modifies run pointer to point to the next run.
* If all_para is FALSE constrain the search to the current para,
* otherwise modify the paragraph pointer if moving into the next paragraph.
*
* Returns TRUE if next run is found, otherwise returns FALSE. */
BOOL ME_NextRun(ME_DisplayItem **para, ME_DisplayItem **run, BOOL all_para)
{
ME_DisplayItem *p = (*run)->next;
while (p->type != diTextEnd)
{
if (p->type == diParagraph) {
if (!all_para) return FALSE;
*para = p;
} else if (p->type == diRun) {
*run = p;
return TRUE;
}
p = p->next;
}
return FALSE;
}
/* Modifies run pointer to point to the previous run.
* If all_para is FALSE constrain the search to the current para,
* otherwise modify the paragraph pointer if moving into the previous paragraph.
*
* Returns TRUE if previous run is found, otherwise returns FALSE. */
BOOL ME_PrevRun(ME_DisplayItem **para, ME_DisplayItem **run, BOOL all_para)
{
ME_DisplayItem *p = (*run)->prev;
while (p->type != diTextStart)
{
if (p->type == diParagraph) {
if (!all_para) return FALSE;
if (p->member.para.prev_para->type == diParagraph)
*para = p->member.para.prev_para;
} else if (p->type == diRun) {
*run = p;
return TRUE;
}
p = p->prev;
}
return FALSE;
}
ME_DisplayItem *ME_FindItemBack(ME_DisplayItem *di, ME_DIType nTypeOrClass)
{
if (!di)
return NULL;
di = di->prev;
while(di!=NULL) {
if (ME_DITypesEqual(di->type, nTypeOrClass))
return di;
di = di->prev;
}
return NULL;
}
ME_DisplayItem *ME_FindItemBackOrHere(ME_DisplayItem *di, ME_DIType nTypeOrClass)
{
while(di!=NULL) {
if (ME_DITypesEqual(di->type, nTypeOrClass))
return di;
di = di->prev;
}
return NULL;
}
ME_DisplayItem *ME_FindItemFwd(ME_DisplayItem *di, ME_DIType nTypeOrClass)
{
if (!di) return NULL;
di = di->next;
while(di!=NULL) {
if (ME_DITypesEqual(di->type, nTypeOrClass))
return di;
di = di->next;
}
return NULL;
}
static const char *ME_GetDITypeName(ME_DIType type)
{
switch(type)
{
case diParagraph: return "diParagraph";
case diRun: return "diRun";
case diCell: return "diCell";
case diTextStart: return "diTextStart";
case diTextEnd: return "diTextEnd";
case diStartRow: return "diStartRow";
default: return "?";
}
}
void ME_DestroyDisplayItem(ME_DisplayItem *item)
{
if (0)
TRACE("type=%s\n", ME_GetDITypeName(item->type));
if (item->type==diParagraph)
{
ME_DestroyString(item->member.para.text);
para_num_clear( &item->member.para.para_num );
}
if (item->type==diRun)
{
if (item->member.run.ole_obj) ME_DeleteReObject(item->member.run.ole_obj);
heap_free( item->member.run.glyphs );
heap_free( item->member.run.clusters );
ME_ReleaseStyle(item->member.run.style);
}
FREE_OBJ(item);
}
ME_DisplayItem *ME_MakeDI(ME_DIType type)
{
ME_DisplayItem *item = ALLOC_OBJ(ME_DisplayItem);
ZeroMemory(item, sizeof(ME_DisplayItem));
item->type = type;
item->prev = item->next = NULL;
return item;
}
void ME_DumpDocument(ME_TextBuffer *buffer)
{
/* FIXME this is useless, */
ME_DisplayItem *pItem = buffer->pFirst;
TRACE("DOCUMENT DUMP START\n");
while(pItem) {
switch(pItem->type)
{
case diTextStart:
TRACE("Start\n");
break;
case diCell:
TRACE("Cell(level=%d%s)\n", pItem->member.cell.nNestingLevel,
!pItem->member.cell.next_cell ? ", END" :
(!pItem->member.cell.prev_cell ? ", START" :""));
break;
case diParagraph:
TRACE("Paragraph(ofs=%d)\n", pItem->member.para.nCharOfs);
if (pItem->member.para.nFlags & MEPF_ROWSTART)
TRACE(" - (Table Row Start)\n");
if (pItem->member.para.nFlags & MEPF_ROWEND)
TRACE(" - (Table Row End)\n");
break;
case diStartRow:
TRACE(" - StartRow\n");
break;
case diRun:
TRACE(" - Run(%s, %d, flags=%x)\n", debugstr_run( &pItem->member.run ),
pItem->member.run.nCharOfs, pItem->member.run.nFlags);
break;
case diTextEnd:
TRACE("End(ofs=%d)\n", pItem->member.para.nCharOfs);
break;
default:
break;
}
pItem = pItem->next;
}
TRACE("DOCUMENT DUMP END\n");
}