1c2c66affSColin Finck /*
2c2c66affSColin Finck * RichEdit - functions working on paragraphs of text (diParagraph).
3c2c66affSColin Finck *
4c2c66affSColin Finck * Copyright 2004 by Krzysztof Foltman
5c2c66affSColin Finck * Copyright 2006 by Phil Krylov
6c2c66affSColin Finck *
7c2c66affSColin Finck * This library is free software; you can redistribute it and/or
8c2c66affSColin Finck * modify it under the terms of the GNU Lesser General Public
9c2c66affSColin Finck * License as published by the Free Software Foundation; either
10c2c66affSColin Finck * version 2.1 of the License, or (at your option) any later version.
11c2c66affSColin Finck *
12c2c66affSColin Finck * This library is distributed in the hope that it will be useful,
13c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of
14c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15c2c66affSColin Finck * Lesser General Public License for more details.
16c2c66affSColin Finck *
17c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public
18c2c66affSColin Finck * License along with this library; if not, write to the Free Software
19c2c66affSColin Finck * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20c2c66affSColin Finck */
21c2c66affSColin Finck
22c2c66affSColin Finck #include "editor.h"
23c2c66affSColin Finck
24c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(richedit);
25c2c66affSColin Finck
mark_para_rewrap(ME_TextEditor * editor,ME_DisplayItem * para)26dbfaf10dSAmine Khaldi void mark_para_rewrap(ME_TextEditor *editor, ME_DisplayItem *para)
27dbfaf10dSAmine Khaldi {
28dbfaf10dSAmine Khaldi para->member.para.nFlags |= MEPF_REWRAP;
29dbfaf10dSAmine Khaldi add_marked_para(editor, para);
30dbfaf10dSAmine Khaldi }
31dbfaf10dSAmine Khaldi
get_di_from_para(ME_Paragraph * para)32dbfaf10dSAmine Khaldi ME_DisplayItem *get_di_from_para(ME_Paragraph *para)
33dbfaf10dSAmine Khaldi {
34dbfaf10dSAmine Khaldi return (ME_DisplayItem *)((ptrdiff_t)para - offsetof(ME_DisplayItem, member));
35dbfaf10dSAmine Khaldi }
36dbfaf10dSAmine Khaldi
make_para(ME_TextEditor * editor)37c2c66affSColin Finck static ME_DisplayItem *make_para(ME_TextEditor *editor)
38c2c66affSColin Finck {
39c2c66affSColin Finck ME_DisplayItem *item = ME_MakeDI(diParagraph);
40c2c66affSColin Finck
41c2c66affSColin Finck ME_SetDefaultParaFormat(editor, &item->member.para.fmt);
42c2c66affSColin Finck item->member.para.nFlags = MEPF_REWRAP;
43dbfaf10dSAmine Khaldi item->member.para.next_marked = item->member.para.prev_marked = NULL;
44dbfaf10dSAmine Khaldi
45c2c66affSColin Finck return item;
46c2c66affSColin Finck }
47c2c66affSColin Finck
destroy_para(ME_TextEditor * editor,ME_DisplayItem * item)48dbfaf10dSAmine Khaldi void destroy_para(ME_TextEditor *editor, ME_DisplayItem *item)
49dbfaf10dSAmine Khaldi {
50dbfaf10dSAmine Khaldi assert(item->type == diParagraph);
51dbfaf10dSAmine Khaldi
52dbfaf10dSAmine Khaldi if (item->member.para.nWidth == editor->nTotalWidth)
53dbfaf10dSAmine Khaldi {
54dbfaf10dSAmine Khaldi item->member.para.nWidth = 0;
55dbfaf10dSAmine Khaldi editor->nTotalWidth = get_total_width(editor);
56dbfaf10dSAmine Khaldi }
57dbfaf10dSAmine Khaldi editor->total_rows -= item->member.para.nRows;
58dbfaf10dSAmine Khaldi ME_DestroyString(item->member.para.text);
59dbfaf10dSAmine Khaldi para_num_clear( &item->member.para.para_num );
60dbfaf10dSAmine Khaldi remove_marked_para(editor, item);
61dbfaf10dSAmine Khaldi ME_DestroyDisplayItem(item);
62dbfaf10dSAmine Khaldi }
63dbfaf10dSAmine Khaldi
get_total_width(ME_TextEditor * editor)64dbfaf10dSAmine Khaldi int get_total_width(ME_TextEditor *editor)
65dbfaf10dSAmine Khaldi {
66dbfaf10dSAmine Khaldi ME_Paragraph *para;
67dbfaf10dSAmine Khaldi int total_width = 0;
68dbfaf10dSAmine Khaldi
69dbfaf10dSAmine Khaldi if (editor->pBuffer->pFirst && editor->pBuffer->pLast)
70dbfaf10dSAmine Khaldi {
71dbfaf10dSAmine Khaldi para = &editor->pBuffer->pFirst->next->member.para;
72dbfaf10dSAmine Khaldi while (para != &editor->pBuffer->pLast->member.para && para->next_para)
73dbfaf10dSAmine Khaldi {
74dbfaf10dSAmine Khaldi total_width = max(total_width, para->nWidth);
75dbfaf10dSAmine Khaldi para = ¶->next_para->member.para;
76dbfaf10dSAmine Khaldi }
77dbfaf10dSAmine Khaldi }
78dbfaf10dSAmine Khaldi
79dbfaf10dSAmine Khaldi return total_width;
80dbfaf10dSAmine Khaldi }
81dbfaf10dSAmine Khaldi
remove_marked_para(ME_TextEditor * editor,ME_DisplayItem * di)82dbfaf10dSAmine Khaldi void remove_marked_para(ME_TextEditor *editor, ME_DisplayItem *di)
83dbfaf10dSAmine Khaldi {
84dbfaf10dSAmine Khaldi ME_DisplayItem *head = editor->first_marked_para;
85dbfaf10dSAmine Khaldi
86dbfaf10dSAmine Khaldi assert(di->type == diParagraph);
87dbfaf10dSAmine Khaldi if (!di->member.para.next_marked && !di->member.para.prev_marked)
88dbfaf10dSAmine Khaldi {
89dbfaf10dSAmine Khaldi if (di == head)
90dbfaf10dSAmine Khaldi editor->first_marked_para = NULL;
91dbfaf10dSAmine Khaldi }
92dbfaf10dSAmine Khaldi else if (di->member.para.next_marked && di->member.para.prev_marked)
93dbfaf10dSAmine Khaldi {
94dbfaf10dSAmine Khaldi di->member.para.prev_marked->member.para.next_marked = di->member.para.next_marked;
95dbfaf10dSAmine Khaldi di->member.para.next_marked->member.para.prev_marked = di->member.para.prev_marked;
96dbfaf10dSAmine Khaldi di->member.para.prev_marked = di->member.para.next_marked = NULL;
97dbfaf10dSAmine Khaldi }
98dbfaf10dSAmine Khaldi else if (di->member.para.next_marked)
99dbfaf10dSAmine Khaldi {
100dbfaf10dSAmine Khaldi assert(di == editor->first_marked_para);
101dbfaf10dSAmine Khaldi editor->first_marked_para = di->member.para.next_marked;
102dbfaf10dSAmine Khaldi di->member.para.next_marked->member.para.prev_marked = NULL;
103dbfaf10dSAmine Khaldi di->member.para.next_marked = NULL;
104dbfaf10dSAmine Khaldi }
105dbfaf10dSAmine Khaldi else
106dbfaf10dSAmine Khaldi {
107dbfaf10dSAmine Khaldi di->member.para.prev_marked->member.para.next_marked = NULL;
108dbfaf10dSAmine Khaldi di->member.para.prev_marked = NULL;
109dbfaf10dSAmine Khaldi }
110dbfaf10dSAmine Khaldi }
111dbfaf10dSAmine Khaldi
add_marked_para(ME_TextEditor * editor,ME_DisplayItem * di)112dbfaf10dSAmine Khaldi void add_marked_para(ME_TextEditor *editor, ME_DisplayItem *di)
113dbfaf10dSAmine Khaldi {
114dbfaf10dSAmine Khaldi ME_DisplayItem *iter = editor->first_marked_para;
115dbfaf10dSAmine Khaldi
116dbfaf10dSAmine Khaldi if (!iter)
117dbfaf10dSAmine Khaldi {
118dbfaf10dSAmine Khaldi editor->first_marked_para = di;
119dbfaf10dSAmine Khaldi return;
120dbfaf10dSAmine Khaldi }
121dbfaf10dSAmine Khaldi while (iter)
122dbfaf10dSAmine Khaldi {
123dbfaf10dSAmine Khaldi if (iter == di)
124dbfaf10dSAmine Khaldi return;
125dbfaf10dSAmine Khaldi else if (di->member.para.nCharOfs < iter->member.para.nCharOfs)
126dbfaf10dSAmine Khaldi {
127dbfaf10dSAmine Khaldi if (iter == editor->first_marked_para)
128dbfaf10dSAmine Khaldi editor->first_marked_para = di;
129dbfaf10dSAmine Khaldi di->member.para.next_marked = iter;
130dbfaf10dSAmine Khaldi iter->member.para.prev_marked = di;
131dbfaf10dSAmine Khaldi break;
132dbfaf10dSAmine Khaldi }
133dbfaf10dSAmine Khaldi else if (di->member.para.nCharOfs >= iter->member.para.nCharOfs)
134dbfaf10dSAmine Khaldi {
135dbfaf10dSAmine Khaldi if (!iter->member.para.next_marked || di->member.para.nCharOfs < iter->member.para.next_marked->member.para.nCharOfs)
136dbfaf10dSAmine Khaldi {
137dbfaf10dSAmine Khaldi if (iter->member.para.next_marked)
138dbfaf10dSAmine Khaldi {
139dbfaf10dSAmine Khaldi di->member.para.next_marked = iter->member.para.next_marked;
140dbfaf10dSAmine Khaldi iter->member.para.next_marked->member.para.prev_marked = di;
141dbfaf10dSAmine Khaldi }
142dbfaf10dSAmine Khaldi di->member.para.prev_marked = iter;
143dbfaf10dSAmine Khaldi iter->member.para.next_marked = di;
144dbfaf10dSAmine Khaldi break;
145dbfaf10dSAmine Khaldi }
146dbfaf10dSAmine Khaldi }
147dbfaf10dSAmine Khaldi iter = iter->member.para.next_marked;
148dbfaf10dSAmine Khaldi }
149dbfaf10dSAmine Khaldi }
150dbfaf10dSAmine Khaldi
ME_MakeFirstParagraph(ME_TextEditor * editor)151c2c66affSColin Finck void ME_MakeFirstParagraph(ME_TextEditor *editor)
152c2c66affSColin Finck {
153dbfaf10dSAmine Khaldi static const WCHAR cr_lf[] = {'\r','\n',0};
154c2c66affSColin Finck ME_Context c;
155c2c66affSColin Finck CHARFORMAT2W cf;
156dbfaf10dSAmine Khaldi const CHARFORMATW *host_cf;
157c2c66affSColin Finck LOGFONTW lf;
158c2c66affSColin Finck HFONT hf;
159c2c66affSColin Finck ME_TextBuffer *text = editor->pBuffer;
160c2c66affSColin Finck ME_DisplayItem *para = make_para(editor);
161c2c66affSColin Finck ME_DisplayItem *run;
162c2c66affSColin Finck ME_Style *style;
163c2c66affSColin Finck int eol_len;
164c2c66affSColin Finck
165c2c66affSColin Finck ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost));
166c2c66affSColin Finck
167c2c66affSColin Finck hf = GetStockObject(SYSTEM_FONT);
168c2c66affSColin Finck assert(hf);
169c2c66affSColin Finck GetObjectW(hf, sizeof(LOGFONTW), &lf);
170c2c66affSColin Finck ZeroMemory(&cf, sizeof(cf));
171c2c66affSColin Finck cf.cbSize = sizeof(cf);
172c2c66affSColin Finck cf.dwMask = CFM_ANIMATION|CFM_BACKCOLOR|CFM_CHARSET|CFM_COLOR|CFM_FACE|CFM_KERNING|CFM_LCID|CFM_OFFSET;
173c2c66affSColin Finck cf.dwMask |= CFM_REVAUTHOR|CFM_SIZE|CFM_SPACING|CFM_STYLE|CFM_UNDERLINETYPE|CFM_WEIGHT;
174c2c66affSColin Finck cf.dwMask |= CFM_ALLCAPS|CFM_BOLD|CFM_DISABLED|CFM_EMBOSS|CFM_HIDDEN;
175c2c66affSColin Finck cf.dwMask |= CFM_IMPRINT|CFM_ITALIC|CFM_LINK|CFM_OUTLINE|CFM_PROTECTED;
176c2c66affSColin Finck cf.dwMask |= CFM_REVISED|CFM_SHADOW|CFM_SMALLCAPS|CFM_STRIKEOUT;
177c2c66affSColin Finck cf.dwMask |= CFM_SUBSCRIPT|CFM_UNDERLINE;
178c2c66affSColin Finck
179c2c66affSColin Finck cf.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR;
180c2c66affSColin Finck lstrcpyW(cf.szFaceName, lf.lfFaceName);
181c2c66affSColin Finck /* Convert system font height from logical units to twips for cf.yHeight */
182c2c66affSColin Finck cf.yHeight = (lf.lfHeight * 72 * 1440) / (c.dpi.cy * c.dpi.cy);
183c2c66affSColin Finck if (lf.lfWeight > FW_NORMAL) cf.dwEffects |= CFE_BOLD;
184c2c66affSColin Finck cf.wWeight = lf.lfWeight;
185c2c66affSColin Finck if (lf.lfItalic) cf.dwEffects |= CFE_ITALIC;
186c2c66affSColin Finck if (lf.lfUnderline) cf.dwEffects |= CFE_UNDERLINE;
187c2c66affSColin Finck cf.bUnderlineType = CFU_UNDERLINE;
188c2c66affSColin Finck if (lf.lfStrikeOut) cf.dwEffects |= CFE_STRIKEOUT;
189c2c66affSColin Finck cf.bPitchAndFamily = lf.lfPitchAndFamily;
190c2c66affSColin Finck cf.bCharSet = lf.lfCharSet;
191c2c66affSColin Finck cf.lcid = GetSystemDefaultLCID();
192c2c66affSColin Finck
193c2c66affSColin Finck style = ME_MakeStyle(&cf);
194c2c66affSColin Finck text->pDefaultStyle = style;
195c2c66affSColin Finck
196dbfaf10dSAmine Khaldi if (ITextHost_TxGetCharFormat(editor->texthost, &host_cf) == S_OK)
197dbfaf10dSAmine Khaldi {
198dbfaf10dSAmine Khaldi ZeroMemory(&cf, sizeof(cf));
199dbfaf10dSAmine Khaldi cf.cbSize = sizeof(cf);
200dbfaf10dSAmine Khaldi cfany_to_cf2w(&cf, (CHARFORMAT2W *)host_cf);
201dbfaf10dSAmine Khaldi ME_SetDefaultCharFormat(editor, &cf);
202dbfaf10dSAmine Khaldi }
203dbfaf10dSAmine Khaldi
204c2c66affSColin Finck eol_len = editor->bEmulateVersion10 ? 2 : 1;
205c2c66affSColin Finck para->member.para.text = ME_MakeStringN( cr_lf, eol_len );
206c2c66affSColin Finck
207c2c66affSColin Finck run = ME_MakeRun(style, MERF_ENDPARA);
208c2c66affSColin Finck run->member.run.nCharOfs = 0;
209c2c66affSColin Finck run->member.run.len = eol_len;
210c2c66affSColin Finck run->member.run.para = ¶->member.para;
211c2c66affSColin Finck
212c2c66affSColin Finck para->member.para.eop_run = &run->member.run;
213c2c66affSColin Finck
214c2c66affSColin Finck ME_InsertBefore(text->pLast, para);
215c2c66affSColin Finck ME_InsertBefore(text->pLast, run);
216c2c66affSColin Finck para->member.para.prev_para = text->pFirst;
217c2c66affSColin Finck para->member.para.next_para = text->pLast;
218c2c66affSColin Finck text->pFirst->member.para.next_para = para;
219c2c66affSColin Finck text->pLast->member.para.prev_para = para;
220c2c66affSColin Finck
221c2c66affSColin Finck text->pLast->member.para.nCharOfs = editor->bEmulateVersion10 ? 2 : 1;
222c2c66affSColin Finck
223dbfaf10dSAmine Khaldi add_marked_para(editor, para);
224c2c66affSColin Finck ME_DestroyContext(&c);
225c2c66affSColin Finck }
226c2c66affSColin Finck
ME_MarkForWrapping(ME_TextEditor * editor,ME_DisplayItem * first,const ME_DisplayItem * last)227c2c66affSColin Finck static void ME_MarkForWrapping(ME_TextEditor *editor, ME_DisplayItem *first, const ME_DisplayItem *last)
228c2c66affSColin Finck {
229c2c66affSColin Finck while(first != last)
230c2c66affSColin Finck {
231dbfaf10dSAmine Khaldi mark_para_rewrap(editor, first);
232c2c66affSColin Finck first = first->member.para.next_para;
233c2c66affSColin Finck }
234c2c66affSColin Finck }
235c2c66affSColin Finck
ME_MarkAllForWrapping(ME_TextEditor * editor)236c2c66affSColin Finck void ME_MarkAllForWrapping(ME_TextEditor *editor)
237c2c66affSColin Finck {
238c2c66affSColin Finck ME_MarkForWrapping(editor, editor->pBuffer->pFirst->member.para.next_para, editor->pBuffer->pLast);
239c2c66affSColin Finck }
240c2c66affSColin Finck
ME_UpdateTableFlags(ME_DisplayItem * para)241c2c66affSColin Finck static void ME_UpdateTableFlags(ME_DisplayItem *para)
242c2c66affSColin Finck {
243c2c66affSColin Finck para->member.para.fmt.dwMask |= PFM_TABLE|PFM_TABLEROWDELIMITER;
244c2c66affSColin Finck if (para->member.para.pCell) {
245c2c66affSColin Finck para->member.para.nFlags |= MEPF_CELL;
246c2c66affSColin Finck } else {
247c2c66affSColin Finck para->member.para.nFlags &= ~MEPF_CELL;
248c2c66affSColin Finck }
249c2c66affSColin Finck if (para->member.para.nFlags & MEPF_ROWEND) {
250c2c66affSColin Finck para->member.para.fmt.wEffects |= PFE_TABLEROWDELIMITER;
251c2c66affSColin Finck } else {
252c2c66affSColin Finck para->member.para.fmt.wEffects &= ~PFE_TABLEROWDELIMITER;
253c2c66affSColin Finck }
254c2c66affSColin Finck if (para->member.para.nFlags & (MEPF_ROWSTART|MEPF_CELL|MEPF_ROWEND))
255c2c66affSColin Finck para->member.para.fmt.wEffects |= PFE_TABLE;
256c2c66affSColin Finck else
257c2c66affSColin Finck para->member.para.fmt.wEffects &= ~PFE_TABLE;
258c2c66affSColin Finck }
259c2c66affSColin Finck
para_num_same_list(const PARAFORMAT2 * item,const PARAFORMAT2 * base)260c2c66affSColin Finck static inline BOOL para_num_same_list( const PARAFORMAT2 *item, const PARAFORMAT2 *base )
261c2c66affSColin Finck {
262c2c66affSColin Finck return item->wNumbering == base->wNumbering &&
263c2c66affSColin Finck item->wNumberingStart == base->wNumberingStart &&
264c2c66affSColin Finck item->wNumberingStyle == base->wNumberingStyle &&
265c2c66affSColin Finck !(item->wNumberingStyle & PFNS_NEWNUMBER);
266c2c66affSColin Finck }
267c2c66affSColin Finck
para_num_get_num(ME_Paragraph * para)268c2c66affSColin Finck static int para_num_get_num( ME_Paragraph *para )
269c2c66affSColin Finck {
270c2c66affSColin Finck ME_DisplayItem *prev;
271c2c66affSColin Finck int num = para->fmt.wNumberingStart;
272c2c66affSColin Finck
273c2c66affSColin Finck for (prev = para->prev_para; prev->type == diParagraph;
274c2c66affSColin Finck para = &prev->member.para, prev = prev->member.para.prev_para, num++)
275c2c66affSColin Finck {
276c2c66affSColin Finck if (!para_num_same_list( &prev->member.para.fmt, ¶->fmt )) break;
277c2c66affSColin Finck }
278c2c66affSColin Finck return num;
279c2c66affSColin Finck }
280c2c66affSColin Finck
para_num_get_str(ME_Paragraph * para,WORD num)281c2c66affSColin Finck static ME_String *para_num_get_str( ME_Paragraph *para, WORD num )
282c2c66affSColin Finck {
283c2c66affSColin Finck /* max 4 Roman letters (representing '8') / decade + '(' + ')' */
284c2c66affSColin Finck ME_String *str = ME_MakeStringEmpty( 20 + 2 );
285c2c66affSColin Finck WCHAR *p;
286c2c66affSColin Finck static const WCHAR fmtW[] = {'%', 'd', 0};
287c2c66affSColin Finck static const WORD letter_base[] = { 1, 26, 26 * 26, 26 * 26 * 26 };
288c2c66affSColin Finck /* roman_base should start on a '5' not a '1', otherwise the 'total' code will need adjusting.
289c2c66affSColin Finck 'N' and 'O' are what MS uses for 5000 and 10000, their version doesn't work well above 30000,
290c2c66affSColin Finck but we'll use 'P' as the obvious extension, this gets us up to 2^16, which is all we care about. */
291c2c66affSColin Finck static const struct
292c2c66affSColin Finck {
293c2c66affSColin Finck int base;
294c2c66affSColin Finck char letter;
295c2c66affSColin Finck }
296c2c66affSColin Finck roman_base[] =
297c2c66affSColin Finck {
298c2c66affSColin Finck {50000, 'P'}, {10000, 'O'}, {5000, 'N'}, {1000, 'M'},
299c2c66affSColin Finck {500, 'D'}, {100, 'C'}, {50, 'L'}, {10, 'X'}, {5, 'V'}, {1, 'I'}
300c2c66affSColin Finck };
301c2c66affSColin Finck int i, len;
302c2c66affSColin Finck WORD letter, total, char_offset = 0;
303c2c66affSColin Finck
304c2c66affSColin Finck if (!str) return NULL;
305c2c66affSColin Finck
306c2c66affSColin Finck p = str->szData;
307c2c66affSColin Finck
308c2c66affSColin Finck if ((para->fmt.wNumberingStyle & 0xf00) == PFNS_PARENS)
309c2c66affSColin Finck *p++ = '(';
310c2c66affSColin Finck
311c2c66affSColin Finck switch (para->fmt.wNumbering)
312c2c66affSColin Finck {
313c2c66affSColin Finck case PFN_ARABIC:
314c2c66affSColin Finck default:
315661b8a2aSAmine Khaldi p += swprintf( p, fmtW, num );
316c2c66affSColin Finck break;
317c2c66affSColin Finck
318c2c66affSColin Finck case PFN_LCLETTER:
319c2c66affSColin Finck char_offset = 'a' - 'A';
320c2c66affSColin Finck /* fall through */
321c2c66affSColin Finck case PFN_UCLETTER:
322c2c66affSColin Finck if (!num) num = 1;
323c2c66affSColin Finck
324c2c66affSColin Finck /* This is not base-26 (or 27) as zeros don't count unless they are leading zeros.
325c2c66affSColin Finck It's simplest to start with the least significant letter, so first calculate how many letters are needed. */
326dbfaf10dSAmine Khaldi for (i = 0, total = 0; i < ARRAY_SIZE( letter_base ); i++)
327c2c66affSColin Finck {
328c2c66affSColin Finck total += letter_base[i];
329c2c66affSColin Finck if (num < total) break;
330c2c66affSColin Finck }
331c2c66affSColin Finck len = i;
332c2c66affSColin Finck for (i = 0; i < len; i++)
333c2c66affSColin Finck {
334c2c66affSColin Finck num -= letter_base[i];
335c2c66affSColin Finck letter = (num / letter_base[i]) % 26;
336c2c66affSColin Finck p[len - i - 1] = letter + 'A' + char_offset;
337c2c66affSColin Finck }
338c2c66affSColin Finck p += len;
339c2c66affSColin Finck *p = 0;
340c2c66affSColin Finck break;
341c2c66affSColin Finck
342c2c66affSColin Finck case PFN_LCROMAN:
343c2c66affSColin Finck char_offset = 'a' - 'A';
344c2c66affSColin Finck /* fall through */
345c2c66affSColin Finck case PFN_UCROMAN:
346c2c66affSColin Finck if (!num) num = 1;
347c2c66affSColin Finck
348dbfaf10dSAmine Khaldi for (i = 0; i < ARRAY_SIZE( roman_base ); i++)
349c2c66affSColin Finck {
350c2c66affSColin Finck if (i > 0)
351c2c66affSColin Finck {
352c2c66affSColin Finck if (i % 2 == 0) /* eg 5000, check for 9000 */
353c2c66affSColin Finck total = roman_base[i].base + 4 * roman_base[i + 1].base;
354c2c66affSColin Finck else /* eg 1000, check for 4000 */
355c2c66affSColin Finck total = 4 * roman_base[i].base;
356c2c66affSColin Finck
357c2c66affSColin Finck if (num / total)
358c2c66affSColin Finck {
359c2c66affSColin Finck *p++ = roman_base[(i & ~1) + 1].letter + char_offset;
360c2c66affSColin Finck *p++ = roman_base[i - 1].letter + char_offset;
361c2c66affSColin Finck num -= total;
362c2c66affSColin Finck continue;
363c2c66affSColin Finck }
364c2c66affSColin Finck }
365c2c66affSColin Finck
366c2c66affSColin Finck len = num / roman_base[i].base;
367c2c66affSColin Finck while (len--)
368c2c66affSColin Finck {
369c2c66affSColin Finck *p++ = roman_base[i].letter + char_offset;
370c2c66affSColin Finck num -= roman_base[i].base;
371c2c66affSColin Finck }
372c2c66affSColin Finck }
373c2c66affSColin Finck *p = 0;
374c2c66affSColin Finck break;
375c2c66affSColin Finck }
376c2c66affSColin Finck
377c2c66affSColin Finck switch (para->fmt.wNumberingStyle & 0xf00)
378c2c66affSColin Finck {
379c2c66affSColin Finck case PFNS_PARENS:
380c2c66affSColin Finck case PFNS_PAREN:
381c2c66affSColin Finck *p++ = ')';
382c2c66affSColin Finck *p = 0;
383c2c66affSColin Finck break;
384c2c66affSColin Finck
385c2c66affSColin Finck case PFNS_PERIOD:
386c2c66affSColin Finck *p++ = '.';
387c2c66affSColin Finck *p = 0;
388c2c66affSColin Finck break;
389c2c66affSColin Finck }
390c2c66affSColin Finck
391c2c66affSColin Finck str->nLen = p - str->szData;
392c2c66affSColin Finck return str;
393c2c66affSColin Finck }
394c2c66affSColin Finck
para_num_init(ME_Context * c,ME_Paragraph * para)395c2c66affSColin Finck void para_num_init( ME_Context *c, ME_Paragraph *para )
396c2c66affSColin Finck {
397c2c66affSColin Finck ME_Style *style;
398c2c66affSColin Finck CHARFORMAT2W cf;
399c2c66affSColin Finck static const WCHAR bullet_font[] = {'S','y','m','b','o','l',0};
400c2c66affSColin Finck static const WCHAR bullet_str[] = {0xb7, 0};
401c2c66affSColin Finck static const WCHAR spaceW[] = {' ', 0};
402c2c66affSColin Finck SIZE sz;
403c2c66affSColin Finck
404661b8a2aSAmine Khaldi if (!para->fmt.wNumbering) return;
405c2c66affSColin Finck if (para->para_num.style && para->para_num.text) return;
406c2c66affSColin Finck
407c2c66affSColin Finck if (!para->para_num.style)
408c2c66affSColin Finck {
409c2c66affSColin Finck style = para->eop_run->style;
410c2c66affSColin Finck
411c2c66affSColin Finck if (para->fmt.wNumbering == PFN_BULLET)
412c2c66affSColin Finck {
413c2c66affSColin Finck cf.cbSize = sizeof(cf);
414c2c66affSColin Finck cf.dwMask = CFM_FACE | CFM_CHARSET;
415c2c66affSColin Finck memcpy( cf.szFaceName, bullet_font, sizeof(bullet_font) );
416c2c66affSColin Finck cf.bCharSet = SYMBOL_CHARSET;
417c2c66affSColin Finck style = ME_ApplyStyle( c->editor, style, &cf );
418c2c66affSColin Finck }
419c2c66affSColin Finck else
420c2c66affSColin Finck {
421c2c66affSColin Finck ME_AddRefStyle( style );
422c2c66affSColin Finck }
423c2c66affSColin Finck
424c2c66affSColin Finck para->para_num.style = style;
425c2c66affSColin Finck }
426c2c66affSColin Finck
427c2c66affSColin Finck if (!para->para_num.text)
428c2c66affSColin Finck {
429c2c66affSColin Finck if (para->fmt.wNumbering != PFN_BULLET)
430c2c66affSColin Finck para->para_num.text = para_num_get_str( para, para_num_get_num( para ) );
431c2c66affSColin Finck else
432c2c66affSColin Finck para->para_num.text = ME_MakeStringConst( bullet_str, 1 );
433c2c66affSColin Finck }
434c2c66affSColin Finck
435661b8a2aSAmine Khaldi select_style( c, para->para_num.style );
436c2c66affSColin Finck GetTextExtentPointW( c->hDC, para->para_num.text->szData, para->para_num.text->nLen, &sz );
437c2c66affSColin Finck para->para_num.width = sz.cx;
438c2c66affSColin Finck GetTextExtentPointW( c->hDC, spaceW, 1, &sz );
439c2c66affSColin Finck para->para_num.width += sz.cx;
440c2c66affSColin Finck }
441c2c66affSColin Finck
para_num_clear(struct para_num * pn)442c2c66affSColin Finck void para_num_clear( struct para_num *pn )
443c2c66affSColin Finck {
444c2c66affSColin Finck if (pn->style)
445c2c66affSColin Finck {
446c2c66affSColin Finck ME_ReleaseStyle( pn->style );
447c2c66affSColin Finck pn->style = NULL;
448c2c66affSColin Finck }
449c2c66affSColin Finck ME_DestroyString( pn->text );
450c2c66affSColin Finck pn->text = NULL;
451c2c66affSColin Finck }
452c2c66affSColin Finck
para_num_clear_list(ME_TextEditor * editor,ME_Paragraph * para,const PARAFORMAT2 * orig_fmt)453dbfaf10dSAmine Khaldi static void para_num_clear_list( ME_TextEditor *editor, ME_Paragraph *para, const PARAFORMAT2 *orig_fmt )
454c2c66affSColin Finck {
455c2c66affSColin Finck do
456c2c66affSColin Finck {
457dbfaf10dSAmine Khaldi mark_para_rewrap(editor, get_di_from_para(para));
458c2c66affSColin Finck para_num_clear( ¶->para_num );
459c2c66affSColin Finck if (para->next_para->type != diParagraph) break;
460c2c66affSColin Finck para = ¶->next_para->member.para;
461c2c66affSColin Finck } while (para_num_same_list( ¶->fmt, orig_fmt ));
462c2c66affSColin Finck }
463c2c66affSColin Finck
ME_SetParaFormat(ME_TextEditor * editor,ME_Paragraph * para,const PARAFORMAT2 * pFmt)464c2c66affSColin Finck static BOOL ME_SetParaFormat(ME_TextEditor *editor, ME_Paragraph *para, const PARAFORMAT2 *pFmt)
465c2c66affSColin Finck {
466c2c66affSColin Finck PARAFORMAT2 copy;
467c2c66affSColin Finck DWORD dwMask;
468c2c66affSColin Finck
469c2c66affSColin Finck assert(para->fmt.cbSize == sizeof(PARAFORMAT2));
470c2c66affSColin Finck dwMask = pFmt->dwMask;
471c2c66affSColin Finck if (pFmt->cbSize < sizeof(PARAFORMAT))
472c2c66affSColin Finck return FALSE;
473c2c66affSColin Finck else if (pFmt->cbSize < sizeof(PARAFORMAT2))
474c2c66affSColin Finck dwMask &= PFM_ALL;
475c2c66affSColin Finck else
476c2c66affSColin Finck dwMask &= PFM_ALL2;
477c2c66affSColin Finck
478c2c66affSColin Finck add_undo_set_para_fmt( editor, para );
479c2c66affSColin Finck
480c2c66affSColin Finck copy = para->fmt;
481c2c66affSColin Finck
482c2c66affSColin Finck #define COPY_FIELD(m, f) \
483c2c66affSColin Finck if (dwMask & (m)) { \
484c2c66affSColin Finck para->fmt.dwMask |= m; \
485c2c66affSColin Finck para->fmt.f = pFmt->f; \
486c2c66affSColin Finck }
487c2c66affSColin Finck
488c2c66affSColin Finck COPY_FIELD(PFM_NUMBERING, wNumbering);
489c2c66affSColin Finck COPY_FIELD(PFM_STARTINDENT, dxStartIndent);
490c2c66affSColin Finck if (dwMask & PFM_OFFSETINDENT)
491c2c66affSColin Finck para->fmt.dxStartIndent += pFmt->dxStartIndent;
492c2c66affSColin Finck COPY_FIELD(PFM_RIGHTINDENT, dxRightIndent);
493c2c66affSColin Finck COPY_FIELD(PFM_OFFSET, dxOffset);
494c2c66affSColin Finck COPY_FIELD(PFM_ALIGNMENT, wAlignment);
495c2c66affSColin Finck if (dwMask & PFM_TABSTOPS)
496c2c66affSColin Finck {
497*40955b44SDoug Lyons para->fmt.cTabCount = max(0, min(pFmt->cTabCount, MAX_TAB_STOPS)); /* Clamp between 0 and MAX_TAB_STOPS */
498*40955b44SDoug Lyons memcpy(para->fmt.rgxTabs, pFmt->rgxTabs, para->fmt.cTabCount*sizeof(LONG));
499c2c66affSColin Finck }
500c2c66affSColin Finck
501c2c66affSColin Finck #define EFFECTS_MASK (PFM_RTLPARA|PFM_KEEP|PFM_KEEPNEXT|PFM_PAGEBREAKBEFORE| \
502c2c66affSColin Finck PFM_NOLINENUMBER|PFM_NOWIDOWCONTROL|PFM_DONOTHYPHEN|PFM_SIDEBYSIDE| \
503c2c66affSColin Finck PFM_TABLE)
504c2c66affSColin Finck /* we take for granted that PFE_xxx is the hiword of the corresponding PFM_xxx */
505c2c66affSColin Finck if (dwMask & EFFECTS_MASK)
506c2c66affSColin Finck {
507c2c66affSColin Finck para->fmt.dwMask |= dwMask & EFFECTS_MASK;
508c2c66affSColin Finck para->fmt.wEffects &= ~HIWORD(dwMask);
509c2c66affSColin Finck para->fmt.wEffects |= pFmt->wEffects & HIWORD(dwMask);
510c2c66affSColin Finck }
511c2c66affSColin Finck #undef EFFECTS_MASK
512c2c66affSColin Finck
513c2c66affSColin Finck COPY_FIELD(PFM_SPACEBEFORE, dySpaceBefore);
514c2c66affSColin Finck COPY_FIELD(PFM_SPACEAFTER, dySpaceAfter);
515c2c66affSColin Finck COPY_FIELD(PFM_LINESPACING, dyLineSpacing);
516c2c66affSColin Finck COPY_FIELD(PFM_STYLE, sStyle);
517c2c66affSColin Finck COPY_FIELD(PFM_LINESPACING, bLineSpacingRule);
518c2c66affSColin Finck COPY_FIELD(PFM_SHADING, wShadingWeight);
519c2c66affSColin Finck COPY_FIELD(PFM_SHADING, wShadingStyle);
520c2c66affSColin Finck COPY_FIELD(PFM_NUMBERINGSTART, wNumberingStart);
521c2c66affSColin Finck COPY_FIELD(PFM_NUMBERINGSTYLE, wNumberingStyle);
522c2c66affSColin Finck COPY_FIELD(PFM_NUMBERINGTAB, wNumberingTab);
523c2c66affSColin Finck COPY_FIELD(PFM_BORDER, wBorderSpace);
524c2c66affSColin Finck COPY_FIELD(PFM_BORDER, wBorderWidth);
525c2c66affSColin Finck COPY_FIELD(PFM_BORDER, wBorders);
526c2c66affSColin Finck
527c2c66affSColin Finck para->fmt.dwMask |= dwMask;
528c2c66affSColin Finck #undef COPY_FIELD
529c2c66affSColin Finck
530c2c66affSColin Finck if (memcmp(©, ¶->fmt, sizeof(PARAFORMAT2)))
531c2c66affSColin Finck {
532dbfaf10dSAmine Khaldi mark_para_rewrap(editor, get_di_from_para(para));
533c2c66affSColin Finck if (((dwMask & PFM_NUMBERING) && (copy.wNumbering != para->fmt.wNumbering)) ||
534c2c66affSColin Finck ((dwMask & PFM_NUMBERINGSTART) && (copy.wNumberingStart != para->fmt.wNumberingStart)) ||
535c2c66affSColin Finck ((dwMask & PFM_NUMBERINGSTYLE) && (copy.wNumberingStyle != para->fmt.wNumberingStyle)))
536c2c66affSColin Finck {
537dbfaf10dSAmine Khaldi para_num_clear_list( editor, para, © );
538c2c66affSColin Finck }
539c2c66affSColin Finck }
540c2c66affSColin Finck
541c2c66affSColin Finck return TRUE;
542c2c66affSColin Finck }
543c2c66affSColin Finck
544c2c66affSColin Finck /* split paragraph at the beginning of the run */
ME_SplitParagraph(ME_TextEditor * editor,ME_DisplayItem * run,ME_Style * style,const WCHAR * eol_str,int eol_len,int paraFlags)545c2c66affSColin Finck ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run,
546c2c66affSColin Finck ME_Style *style, const WCHAR *eol_str, int eol_len,
547c2c66affSColin Finck int paraFlags)
548c2c66affSColin Finck {
549c2c66affSColin Finck ME_DisplayItem *next_para = NULL;
550c2c66affSColin Finck ME_DisplayItem *run_para = NULL;
551c2c66affSColin Finck ME_DisplayItem *new_para = make_para(editor);
552c2c66affSColin Finck ME_DisplayItem *end_run;
553c2c66affSColin Finck int ofs, i;
554c2c66affSColin Finck ME_DisplayItem *pp;
555c2c66affSColin Finck int run_flags = MERF_ENDPARA;
556c2c66affSColin Finck
557c2c66affSColin Finck if (!editor->bEmulateVersion10) { /* v4.1 */
558c2c66affSColin Finck /* At most 1 of MEPF_CELL, MEPF_ROWSTART, or MEPF_ROWEND should be set. */
559c2c66affSColin Finck assert(!(paraFlags & ~(MEPF_CELL|MEPF_ROWSTART|MEPF_ROWEND)));
560c2c66affSColin Finck assert(!(paraFlags & (paraFlags-1)));
561c2c66affSColin Finck if (paraFlags == MEPF_CELL)
562c2c66affSColin Finck run_flags |= MERF_ENDCELL;
563c2c66affSColin Finck else if (paraFlags == MEPF_ROWSTART)
564c2c66affSColin Finck run_flags |= MERF_TABLESTART|MERF_HIDDEN;
565c2c66affSColin Finck } else { /* v1.0 - v3.0 */
566c2c66affSColin Finck assert(!(paraFlags & (MEPF_CELL|MEPF_ROWSTART|MEPF_ROWEND)));
567c2c66affSColin Finck }
568c2c66affSColin Finck assert(run->type == diRun);
569c2c66affSColin Finck run_para = ME_GetParagraph(run);
570c2c66affSColin Finck assert(run_para->member.para.fmt.cbSize == sizeof(PARAFORMAT2));
571c2c66affSColin Finck
572c2c66affSColin Finck /* Clear any cached para numbering following this paragraph */
573c2c66affSColin Finck if (run_para->member.para.fmt.wNumbering)
574dbfaf10dSAmine Khaldi para_num_clear_list( editor, &run_para->member.para, &run_para->member.para.fmt );
575c2c66affSColin Finck
576c2c66affSColin Finck new_para->member.para.text = ME_VSplitString( run_para->member.para.text, run->member.run.nCharOfs );
577c2c66affSColin Finck
578c2c66affSColin Finck end_run = ME_MakeRun(style, run_flags);
579c2c66affSColin Finck ofs = end_run->member.run.nCharOfs = run->member.run.nCharOfs;
580c2c66affSColin Finck end_run->member.run.len = eol_len;
581c2c66affSColin Finck end_run->member.run.para = run->member.run.para;
582c2c66affSColin Finck ME_AppendString( run_para->member.para.text, eol_str, eol_len );
583c2c66affSColin Finck next_para = run_para->member.para.next_para;
584c2c66affSColin Finck assert(next_para == ME_FindItemFwd(run_para, diParagraphOrEnd));
585c2c66affSColin Finck
586c2c66affSColin Finck add_undo_join_paras( editor, run_para->member.para.nCharOfs + ofs );
587c2c66affSColin Finck
588c2c66affSColin Finck /* Update selection cursors to point to the correct paragraph. */
589c2c66affSColin Finck for (i = 0; i < editor->nCursors; i++) {
590c2c66affSColin Finck if (editor->pCursors[i].pPara == run_para &&
591c2c66affSColin Finck run->member.run.nCharOfs <= editor->pCursors[i].pRun->member.run.nCharOfs)
592c2c66affSColin Finck {
593c2c66affSColin Finck editor->pCursors[i].pPara = new_para;
594c2c66affSColin Finck }
595c2c66affSColin Finck }
596c2c66affSColin Finck
597c2c66affSColin Finck /* the new paragraph will have a different starting offset, so let's update its runs */
598c2c66affSColin Finck pp = run;
599c2c66affSColin Finck while(pp->type == diRun) {
600c2c66affSColin Finck pp->member.run.nCharOfs -= ofs;
601c2c66affSColin Finck pp->member.run.para = &new_para->member.para;
602c2c66affSColin Finck pp = ME_FindItemFwd(pp, diRunOrParagraphOrEnd);
603c2c66affSColin Finck }
604c2c66affSColin Finck new_para->member.para.nCharOfs = run_para->member.para.nCharOfs + ofs;
605c2c66affSColin Finck new_para->member.para.nCharOfs += eol_len;
606dbfaf10dSAmine Khaldi new_para->member.para.nFlags = 0;
607dbfaf10dSAmine Khaldi mark_para_rewrap(editor, new_para);
608c2c66affSColin Finck
609c2c66affSColin Finck /* FIXME initialize format style and call ME_SetParaFormat blah blah */
610c2c66affSColin Finck new_para->member.para.fmt = run_para->member.para.fmt;
611c2c66affSColin Finck new_para->member.para.border = run_para->member.para.border;
612c2c66affSColin Finck
613c2c66affSColin Finck /* insert paragraph into paragraph double linked list */
614c2c66affSColin Finck new_para->member.para.prev_para = run_para;
615c2c66affSColin Finck new_para->member.para.next_para = next_para;
616c2c66affSColin Finck run_para->member.para.next_para = new_para;
617c2c66affSColin Finck next_para->member.para.prev_para = new_para;
618c2c66affSColin Finck
619c2c66affSColin Finck /* insert end run of the old paragraph, and new paragraph, into DI double linked list */
620c2c66affSColin Finck ME_InsertBefore(run, new_para);
621c2c66affSColin Finck ME_InsertBefore(new_para, end_run);
622c2c66affSColin Finck
623c2c66affSColin Finck /* Fix up the paras' eop_run ptrs */
624c2c66affSColin Finck new_para->member.para.eop_run = run_para->member.para.eop_run;
625c2c66affSColin Finck run_para->member.para.eop_run = &end_run->member.run;
626c2c66affSColin Finck
627c2c66affSColin Finck if (!editor->bEmulateVersion10) { /* v4.1 */
628c2c66affSColin Finck if (paraFlags & (MEPF_ROWSTART|MEPF_CELL))
629c2c66affSColin Finck {
630c2c66affSColin Finck ME_DisplayItem *cell = ME_MakeDI(diCell);
631c2c66affSColin Finck ME_InsertBefore(new_para, cell);
632c2c66affSColin Finck new_para->member.para.pCell = cell;
633c2c66affSColin Finck cell->member.cell.next_cell = NULL;
634c2c66affSColin Finck if (paraFlags & MEPF_ROWSTART)
635c2c66affSColin Finck {
636c2c66affSColin Finck run_para->member.para.nFlags |= MEPF_ROWSTART;
637c2c66affSColin Finck cell->member.cell.prev_cell = NULL;
638c2c66affSColin Finck cell->member.cell.parent_cell = run_para->member.para.pCell;
639c2c66affSColin Finck if (run_para->member.para.pCell)
640c2c66affSColin Finck cell->member.cell.nNestingLevel = run_para->member.para.pCell->member.cell.nNestingLevel + 1;
641c2c66affSColin Finck else
642c2c66affSColin Finck cell->member.cell.nNestingLevel = 1;
643c2c66affSColin Finck } else {
644c2c66affSColin Finck cell->member.cell.prev_cell = run_para->member.para.pCell;
645c2c66affSColin Finck assert(cell->member.cell.prev_cell);
646c2c66affSColin Finck cell->member.cell.prev_cell->member.cell.next_cell = cell;
647c2c66affSColin Finck assert(run_para->member.para.nFlags & MEPF_CELL);
648c2c66affSColin Finck assert(!(run_para->member.para.nFlags & MEPF_ROWSTART));
649c2c66affSColin Finck cell->member.cell.nNestingLevel = cell->member.cell.prev_cell->member.cell.nNestingLevel;
650c2c66affSColin Finck cell->member.cell.parent_cell = cell->member.cell.prev_cell->member.cell.parent_cell;
651c2c66affSColin Finck }
652c2c66affSColin Finck } else if (paraFlags & MEPF_ROWEND) {
653c2c66affSColin Finck run_para->member.para.nFlags |= MEPF_ROWEND;
654c2c66affSColin Finck run_para->member.para.pCell = run_para->member.para.pCell->member.cell.parent_cell;
655c2c66affSColin Finck new_para->member.para.pCell = run_para->member.para.pCell;
656c2c66affSColin Finck assert(run_para->member.para.prev_para->member.para.nFlags & MEPF_CELL);
657c2c66affSColin Finck assert(!(run_para->member.para.prev_para->member.para.nFlags & MEPF_ROWSTART));
658c2c66affSColin Finck if (new_para->member.para.pCell != new_para->member.para.next_para->member.para.pCell
659c2c66affSColin Finck && new_para->member.para.next_para->member.para.pCell
660c2c66affSColin Finck && !new_para->member.para.next_para->member.para.pCell->member.cell.prev_cell)
661c2c66affSColin Finck {
662c2c66affSColin Finck /* Row starts just after the row that was ended. */
663c2c66affSColin Finck new_para->member.para.nFlags |= MEPF_ROWSTART;
664c2c66affSColin Finck }
665c2c66affSColin Finck } else {
666c2c66affSColin Finck new_para->member.para.pCell = run_para->member.para.pCell;
667c2c66affSColin Finck }
668c2c66affSColin Finck ME_UpdateTableFlags(run_para);
669c2c66affSColin Finck ME_UpdateTableFlags(new_para);
670c2c66affSColin Finck }
671c2c66affSColin Finck
672c2c66affSColin Finck /* force rewrap of the */
673dbfaf10dSAmine Khaldi if (run_para->member.para.prev_para->type == diParagraph)
674dbfaf10dSAmine Khaldi mark_para_rewrap(editor, run_para->member.para.prev_para);
675dbfaf10dSAmine Khaldi
676dbfaf10dSAmine Khaldi mark_para_rewrap(editor, new_para->member.para.prev_para);
677c2c66affSColin Finck
678c2c66affSColin Finck /* we've added the end run, so we need to modify nCharOfs in the next paragraphs */
679c2c66affSColin Finck ME_PropagateCharOffset(next_para, eol_len);
680c2c66affSColin Finck editor->nParagraphs++;
681c2c66affSColin Finck
682c2c66affSColin Finck return new_para;
683c2c66affSColin Finck }
684c2c66affSColin Finck
685c2c66affSColin Finck /* join tp with tp->member.para.next_para, keeping tp's style; this
686c2c66affSColin Finck * is consistent with the original */
ME_JoinParagraphs(ME_TextEditor * editor,ME_DisplayItem * tp,BOOL keepFirstParaFormat)687c2c66affSColin Finck ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp,
688c2c66affSColin Finck BOOL keepFirstParaFormat)
689c2c66affSColin Finck {
690c2c66affSColin Finck ME_DisplayItem *pNext, *pFirstRunInNext, *pRun, *pTmp, *pCell = NULL;
691c2c66affSColin Finck int i, shift;
692c2c66affSColin Finck int end_len;
693c2c66affSColin Finck CHARFORMAT2W fmt;
694c2c66affSColin Finck ME_Cursor startCur, endCur;
695c2c66affSColin Finck ME_String *eol_str;
696c2c66affSColin Finck
697c2c66affSColin Finck assert(tp->type == diParagraph);
698c2c66affSColin Finck assert(tp->member.para.next_para);
699c2c66affSColin Finck assert(tp->member.para.next_para->type == diParagraph);
700c2c66affSColin Finck
701c2c66affSColin Finck /* Clear any cached para numbering following this paragraph */
702c2c66affSColin Finck if (tp->member.para.fmt.wNumbering)
703dbfaf10dSAmine Khaldi para_num_clear_list( editor, &tp->member.para, &tp->member.para.fmt );
704c2c66affSColin Finck
705c2c66affSColin Finck pNext = tp->member.para.next_para;
706c2c66affSColin Finck
707c2c66affSColin Finck /* Need to locate end-of-paragraph run here, in order to know end_len */
708c2c66affSColin Finck pRun = ME_FindItemBack(pNext, diRunOrParagraph);
709c2c66affSColin Finck
710c2c66affSColin Finck assert(pRun);
711c2c66affSColin Finck assert(pRun->type == diRun);
712c2c66affSColin Finck assert(pRun->member.run.nFlags & MERF_ENDPARA);
713c2c66affSColin Finck
714c2c66affSColin Finck end_len = pRun->member.run.len;
715c2c66affSColin Finck eol_str = ME_VSplitString( tp->member.para.text, pRun->member.run.nCharOfs );
716c2c66affSColin Finck ME_AppendString( tp->member.para.text, pNext->member.para.text->szData, pNext->member.para.text->nLen );
717c2c66affSColin Finck
718c2c66affSColin Finck /* null char format operation to store the original char format for the ENDPARA run */
719c2c66affSColin Finck ME_InitCharFormat2W(&fmt);
720c2c66affSColin Finck endCur.pPara = pNext;
721c2c66affSColin Finck endCur.pRun = ME_FindItemFwd(pNext, diRun);
722c2c66affSColin Finck endCur.nOffset = 0;
723c2c66affSColin Finck startCur = endCur;
724c2c66affSColin Finck ME_PrevRun(&startCur.pPara, &startCur.pRun, TRUE);
725c2c66affSColin Finck ME_SetCharFormat(editor, &startCur, &endCur, &fmt);
726c2c66affSColin Finck
727c2c66affSColin Finck if (!editor->bEmulateVersion10) { /* v4.1 */
728c2c66affSColin Finck /* Table cell/row properties are always moved over from the removed para. */
729c2c66affSColin Finck tp->member.para.nFlags = pNext->member.para.nFlags;
730c2c66affSColin Finck tp->member.para.pCell = pNext->member.para.pCell;
731c2c66affSColin Finck
732c2c66affSColin Finck /* Remove cell boundary if it is between the end paragraph run and the next
733c2c66affSColin Finck * paragraph display item. */
734c2c66affSColin Finck for (pTmp = pRun->next; pTmp != pNext; pTmp = pTmp->next)
735c2c66affSColin Finck {
736c2c66affSColin Finck if (pTmp->type == diCell)
737c2c66affSColin Finck {
738c2c66affSColin Finck pCell = pTmp;
739c2c66affSColin Finck break;
740c2c66affSColin Finck }
741c2c66affSColin Finck }
742c2c66affSColin Finck }
743c2c66affSColin Finck
744c2c66affSColin Finck add_undo_split_para( editor, &pNext->member.para, eol_str, pCell ? &pCell->member.cell : NULL );
745c2c66affSColin Finck
746c2c66affSColin Finck if (pCell)
747c2c66affSColin Finck {
748c2c66affSColin Finck ME_Remove( pCell );
749c2c66affSColin Finck if (pCell->member.cell.prev_cell)
750c2c66affSColin Finck pCell->member.cell.prev_cell->member.cell.next_cell = pCell->member.cell.next_cell;
751c2c66affSColin Finck if (pCell->member.cell.next_cell)
752c2c66affSColin Finck pCell->member.cell.next_cell->member.cell.prev_cell = pCell->member.cell.prev_cell;
753c2c66affSColin Finck ME_DestroyDisplayItem( pCell );
754c2c66affSColin Finck }
755c2c66affSColin Finck
756c2c66affSColin Finck if (!keepFirstParaFormat)
757c2c66affSColin Finck {
758c2c66affSColin Finck add_undo_set_para_fmt( editor, &tp->member.para );
759c2c66affSColin Finck tp->member.para.fmt = pNext->member.para.fmt;
760c2c66affSColin Finck tp->member.para.border = pNext->member.para.border;
761c2c66affSColin Finck }
762c2c66affSColin Finck
763c2c66affSColin Finck shift = pNext->member.para.nCharOfs - tp->member.para.nCharOfs - end_len;
764c2c66affSColin Finck
765c2c66affSColin Finck pFirstRunInNext = ME_FindItemFwd(pNext, diRunOrParagraph);
766c2c66affSColin Finck
767c2c66affSColin Finck assert(pFirstRunInNext->type == diRun);
768c2c66affSColin Finck
769c2c66affSColin Finck /* Update selection cursors so they don't point to the removed end
770c2c66affSColin Finck * paragraph run, and point to the correct paragraph. */
771c2c66affSColin Finck for (i=0; i < editor->nCursors; i++) {
772c2c66affSColin Finck if (editor->pCursors[i].pRun == pRun) {
773c2c66affSColin Finck editor->pCursors[i].pRun = pFirstRunInNext;
774c2c66affSColin Finck editor->pCursors[i].nOffset = 0;
775c2c66affSColin Finck } else if (editor->pCursors[i].pPara == pNext) {
776c2c66affSColin Finck editor->pCursors[i].pPara = tp;
777c2c66affSColin Finck }
778c2c66affSColin Finck }
779c2c66affSColin Finck
780c2c66affSColin Finck pTmp = pNext;
781c2c66affSColin Finck do {
782c2c66affSColin Finck pTmp = ME_FindItemFwd(pTmp, diRunOrParagraphOrEnd);
783c2c66affSColin Finck if (pTmp->type != diRun)
784c2c66affSColin Finck break;
785c2c66affSColin Finck TRACE("shifting %s by %d (previous %d)\n", debugstr_run( &pTmp->member.run ), shift, pTmp->member.run.nCharOfs);
786c2c66affSColin Finck pTmp->member.run.nCharOfs += shift;
787c2c66affSColin Finck pTmp->member.run.para = &tp->member.para;
788c2c66affSColin Finck } while(1);
789c2c66affSColin Finck
790c2c66affSColin Finck /* Fix up the para's eop_run ptr */
791c2c66affSColin Finck tp->member.para.eop_run = pNext->member.para.eop_run;
792c2c66affSColin Finck
793c2c66affSColin Finck ME_Remove(pRun);
794c2c66affSColin Finck ME_DestroyDisplayItem(pRun);
795c2c66affSColin Finck
796c2c66affSColin Finck if (editor->pLastSelStartPara == pNext)
797c2c66affSColin Finck editor->pLastSelStartPara = tp;
798c2c66affSColin Finck if (editor->pLastSelEndPara == pNext)
799c2c66affSColin Finck editor->pLastSelEndPara = tp;
800c2c66affSColin Finck
801c2c66affSColin Finck tp->member.para.next_para = pNext->member.para.next_para;
802c2c66affSColin Finck pNext->member.para.next_para->member.para.prev_para = tp;
803c2c66affSColin Finck ME_Remove(pNext);
804dbfaf10dSAmine Khaldi destroy_para(editor, pNext);
805c2c66affSColin Finck
806c2c66affSColin Finck ME_PropagateCharOffset(tp->member.para.next_para, -end_len);
807c2c66affSColin Finck
808c2c66affSColin Finck ME_CheckCharOffsets(editor);
809c2c66affSColin Finck
810c2c66affSColin Finck editor->nParagraphs--;
811dbfaf10dSAmine Khaldi mark_para_rewrap(editor, tp);
812c2c66affSColin Finck return tp;
813c2c66affSColin Finck }
814c2c66affSColin Finck
ME_GetParagraph(ME_DisplayItem * item)815c2c66affSColin Finck ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *item) {
816c2c66affSColin Finck return ME_FindItemBackOrHere(item, diParagraph);
817c2c66affSColin Finck }
818c2c66affSColin Finck
ME_DumpParaStyleToBuf(const PARAFORMAT2 * pFmt,char buf[2048])819c2c66affSColin Finck void ME_DumpParaStyleToBuf(const PARAFORMAT2 *pFmt, char buf[2048])
820c2c66affSColin Finck {
821c2c66affSColin Finck char *p;
822c2c66affSColin Finck p = buf;
823c2c66affSColin Finck
824c2c66affSColin Finck #define DUMP(mask, name, fmt, field) \
825c2c66affSColin Finck if (pFmt->dwMask & (mask)) p += sprintf(p, "%-22s" fmt "\n", name, pFmt->field); \
826c2c66affSColin Finck else p += sprintf(p, "%-22sN/A\n", name);
827c2c66affSColin Finck
828c2c66affSColin Finck /* we take for granted that PFE_xxx is the hiword of the corresponding PFM_xxx */
829c2c66affSColin Finck #define DUMP_EFFECT(mask, name) \
830c2c66affSColin Finck p += sprintf(p, "%-22s%s\n", name, (pFmt->dwMask & (mask)) ? ((pFmt->wEffects & ((mask) >> 16)) ? "yes" : "no") : "N/A");
831c2c66affSColin Finck
832c2c66affSColin Finck DUMP(PFM_NUMBERING, "Numbering:", "%u", wNumbering);
833c2c66affSColin Finck DUMP_EFFECT(PFM_DONOTHYPHEN, "Disable auto-hyphen:");
834c2c66affSColin Finck DUMP_EFFECT(PFM_KEEP, "No page break in para:");
835c2c66affSColin Finck DUMP_EFFECT(PFM_KEEPNEXT, "No page break in para & next:");
836c2c66affSColin Finck DUMP_EFFECT(PFM_NOLINENUMBER, "No line number:");
837c2c66affSColin Finck DUMP_EFFECT(PFM_NOWIDOWCONTROL, "No widow & orphan:");
838c2c66affSColin Finck DUMP_EFFECT(PFM_PAGEBREAKBEFORE, "Page break before:");
839c2c66affSColin Finck DUMP_EFFECT(PFM_RTLPARA, "RTL para:");
840c2c66affSColin Finck DUMP_EFFECT(PFM_SIDEBYSIDE, "Side by side:");
841c2c66affSColin Finck DUMP_EFFECT(PFM_TABLE, "Table:");
842c2c66affSColin Finck DUMP(PFM_OFFSETINDENT, "Offset indent:", "%d", dxStartIndent);
843c2c66affSColin Finck DUMP(PFM_STARTINDENT, "Start indent:", "%d", dxStartIndent);
844c2c66affSColin Finck DUMP(PFM_RIGHTINDENT, "Right indent:", "%d", dxRightIndent);
845c2c66affSColin Finck DUMP(PFM_OFFSET, "Offset:", "%d", dxOffset);
846c2c66affSColin Finck if (pFmt->dwMask & PFM_ALIGNMENT) {
847c2c66affSColin Finck switch (pFmt->wAlignment) {
848c2c66affSColin Finck case PFA_LEFT : p += sprintf(p, "Alignment: left\n"); break;
849c2c66affSColin Finck case PFA_RIGHT : p += sprintf(p, "Alignment: right\n"); break;
850c2c66affSColin Finck case PFA_CENTER : p += sprintf(p, "Alignment: center\n"); break;
851c2c66affSColin Finck case PFA_JUSTIFY: p += sprintf(p, "Alignment: justify\n"); break;
852c2c66affSColin Finck default : p += sprintf(p, "Alignment: incorrect %d\n", pFmt->wAlignment); break;
853c2c66affSColin Finck }
854c2c66affSColin Finck }
855c2c66affSColin Finck else p += sprintf(p, "Alignment: N/A\n");
856c2c66affSColin Finck DUMP(PFM_TABSTOPS, "Tab Stops:", "%d", cTabCount);
857c2c66affSColin Finck if (pFmt->dwMask & PFM_TABSTOPS) {
858c2c66affSColin Finck int i;
859c2c66affSColin Finck p += sprintf(p, "\t");
860c2c66affSColin Finck for (i = 0; i < pFmt->cTabCount; i++) p += sprintf(p, "%x ", pFmt->rgxTabs[i]);
861c2c66affSColin Finck p += sprintf(p, "\n");
862c2c66affSColin Finck }
863c2c66affSColin Finck DUMP(PFM_SPACEBEFORE, "Space Before:", "%d", dySpaceBefore);
864c2c66affSColin Finck DUMP(PFM_SPACEAFTER, "Space After:", "%d", dySpaceAfter);
865c2c66affSColin Finck DUMP(PFM_LINESPACING, "Line spacing:", "%d", dyLineSpacing);
866c2c66affSColin Finck DUMP(PFM_STYLE, "Text style:", "%d", sStyle);
867c2c66affSColin Finck DUMP(PFM_LINESPACING, "Line spacing rule:", "%u", bLineSpacingRule);
868c2c66affSColin Finck /* bOutlineLevel should be 0 */
869c2c66affSColin Finck DUMP(PFM_SHADING, "Shading Weight:", "%u", wShadingWeight);
870c2c66affSColin Finck DUMP(PFM_SHADING, "Shading Style:", "%u", wShadingStyle);
871c2c66affSColin Finck DUMP(PFM_NUMBERINGSTART, "Numbering Start:", "%u", wNumberingStart);
872c2c66affSColin Finck DUMP(PFM_NUMBERINGSTYLE, "Numbering Style:", "0x%x", wNumberingStyle);
873c2c66affSColin Finck DUMP(PFM_NUMBERINGTAB, "Numbering Tab:", "%u", wNumberingStyle);
874c2c66affSColin Finck DUMP(PFM_BORDER, "Border Space:", "%u", wBorderSpace);
875c2c66affSColin Finck DUMP(PFM_BORDER, "Border Width:", "%u", wBorderWidth);
876c2c66affSColin Finck DUMP(PFM_BORDER, "Borders:", "%u", wBorders);
877c2c66affSColin Finck
878c2c66affSColin Finck #undef DUMP
879c2c66affSColin Finck #undef DUMP_EFFECT
880c2c66affSColin Finck }
881c2c66affSColin Finck
882c2c66affSColin Finck void
ME_GetSelectionParas(ME_TextEditor * editor,ME_DisplayItem ** para,ME_DisplayItem ** para_end)883c2c66affSColin Finck ME_GetSelectionParas(ME_TextEditor *editor, ME_DisplayItem **para, ME_DisplayItem **para_end)
884c2c66affSColin Finck {
885c2c66affSColin Finck ME_Cursor *pEndCursor = &editor->pCursors[1];
886c2c66affSColin Finck
887c2c66affSColin Finck *para = editor->pCursors[0].pPara;
888c2c66affSColin Finck *para_end = editor->pCursors[1].pPara;
889c2c66affSColin Finck if (*para == *para_end)
890c2c66affSColin Finck return;
891c2c66affSColin Finck
892c2c66affSColin Finck if ((*para_end)->member.para.nCharOfs < (*para)->member.para.nCharOfs) {
893c2c66affSColin Finck ME_DisplayItem *tmp = *para;
894c2c66affSColin Finck
895c2c66affSColin Finck *para = *para_end;
896c2c66affSColin Finck *para_end = tmp;
897c2c66affSColin Finck pEndCursor = &editor->pCursors[0];
898c2c66affSColin Finck }
899c2c66affSColin Finck
900c2c66affSColin Finck /* The paragraph at the end of a non-empty selection isn't included
901c2c66affSColin Finck * if the selection ends at the start of the paragraph. */
902c2c66affSColin Finck if (!pEndCursor->pRun->member.run.nCharOfs && !pEndCursor->nOffset)
903c2c66affSColin Finck *para_end = (*para_end)->member.para.prev_para;
904c2c66affSColin Finck }
905c2c66affSColin Finck
906c2c66affSColin Finck
ME_SetSelectionParaFormat(ME_TextEditor * editor,const PARAFORMAT2 * pFmt)907c2c66affSColin Finck BOOL ME_SetSelectionParaFormat(ME_TextEditor *editor, const PARAFORMAT2 *pFmt)
908c2c66affSColin Finck {
909c2c66affSColin Finck ME_DisplayItem *para, *para_end;
910c2c66affSColin Finck
911c2c66affSColin Finck ME_GetSelectionParas(editor, ¶, ¶_end);
912c2c66affSColin Finck
913c2c66affSColin Finck do {
914c2c66affSColin Finck ME_SetParaFormat(editor, ¶->member.para, pFmt);
915c2c66affSColin Finck if (para == para_end)
916c2c66affSColin Finck break;
917c2c66affSColin Finck para = para->member.para.next_para;
918c2c66affSColin Finck } while(1);
919c2c66affSColin Finck
920c2c66affSColin Finck return TRUE;
921c2c66affSColin Finck }
922c2c66affSColin Finck
ME_GetParaFormat(ME_TextEditor * editor,const ME_DisplayItem * para,PARAFORMAT2 * pFmt)923c2c66affSColin Finck static void ME_GetParaFormat(ME_TextEditor *editor,
924c2c66affSColin Finck const ME_DisplayItem *para,
925c2c66affSColin Finck PARAFORMAT2 *pFmt)
926c2c66affSColin Finck {
927c2c66affSColin Finck UINT cbSize = pFmt->cbSize;
928c2c66affSColin Finck if (pFmt->cbSize >= sizeof(PARAFORMAT2)) {
929c2c66affSColin Finck *pFmt = para->member.para.fmt;
930c2c66affSColin Finck } else {
931c2c66affSColin Finck CopyMemory(pFmt, ¶->member.para.fmt, pFmt->cbSize);
932c2c66affSColin Finck pFmt->dwMask &= PFM_ALL;
933c2c66affSColin Finck }
934c2c66affSColin Finck pFmt->cbSize = cbSize;
935c2c66affSColin Finck }
936c2c66affSColin Finck
ME_GetSelectionParaFormat(ME_TextEditor * editor,PARAFORMAT2 * pFmt)937c2c66affSColin Finck void ME_GetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt)
938c2c66affSColin Finck {
939c2c66affSColin Finck ME_DisplayItem *para, *para_end;
940c2c66affSColin Finck PARAFORMAT2 *curFmt;
941c2c66affSColin Finck
942c2c66affSColin Finck if (pFmt->cbSize < sizeof(PARAFORMAT)) {
943c2c66affSColin Finck pFmt->dwMask = 0;
944c2c66affSColin Finck return;
945c2c66affSColin Finck }
946c2c66affSColin Finck
947c2c66affSColin Finck ME_GetSelectionParas(editor, ¶, ¶_end);
948c2c66affSColin Finck
949c2c66affSColin Finck ME_GetParaFormat(editor, para, pFmt);
950c2c66affSColin Finck
951c2c66affSColin Finck /* Invalidate values that change across the selected paragraphs. */
952c2c66affSColin Finck while (para != para_end)
953c2c66affSColin Finck {
954c2c66affSColin Finck para = para->member.para.next_para;
955c2c66affSColin Finck curFmt = ¶->member.para.fmt;
956c2c66affSColin Finck
957c2c66affSColin Finck #define CHECK_FIELD(m, f) \
958c2c66affSColin Finck if (pFmt->f != curFmt->f) pFmt->dwMask &= ~(m);
959c2c66affSColin Finck
960c2c66affSColin Finck CHECK_FIELD(PFM_NUMBERING, wNumbering);
961c2c66affSColin Finck CHECK_FIELD(PFM_STARTINDENT, dxStartIndent);
962c2c66affSColin Finck CHECK_FIELD(PFM_RIGHTINDENT, dxRightIndent);
963c2c66affSColin Finck CHECK_FIELD(PFM_OFFSET, dxOffset);
964c2c66affSColin Finck CHECK_FIELD(PFM_ALIGNMENT, wAlignment);
965c2c66affSColin Finck if (pFmt->dwMask & PFM_TABSTOPS) {
966c2c66affSColin Finck if (pFmt->cTabCount != para->member.para.fmt.cTabCount ||
967c2c66affSColin Finck memcmp(pFmt->rgxTabs, curFmt->rgxTabs, curFmt->cTabCount*sizeof(int)))
968c2c66affSColin Finck pFmt->dwMask &= ~PFM_TABSTOPS;
969c2c66affSColin Finck }
970c2c66affSColin Finck
971c2c66affSColin Finck if (pFmt->dwMask >= sizeof(PARAFORMAT2))
972c2c66affSColin Finck {
973c2c66affSColin Finck pFmt->dwMask &= ~((pFmt->wEffects ^ curFmt->wEffects) << 16);
974c2c66affSColin Finck CHECK_FIELD(PFM_SPACEBEFORE, dySpaceBefore);
975c2c66affSColin Finck CHECK_FIELD(PFM_SPACEAFTER, dySpaceAfter);
976c2c66affSColin Finck CHECK_FIELD(PFM_LINESPACING, dyLineSpacing);
977c2c66affSColin Finck CHECK_FIELD(PFM_STYLE, sStyle);
978c2c66affSColin Finck CHECK_FIELD(PFM_SPACEAFTER, bLineSpacingRule);
979c2c66affSColin Finck CHECK_FIELD(PFM_SHADING, wShadingWeight);
980c2c66affSColin Finck CHECK_FIELD(PFM_SHADING, wShadingStyle);
981c2c66affSColin Finck CHECK_FIELD(PFM_NUMBERINGSTART, wNumberingStart);
982c2c66affSColin Finck CHECK_FIELD(PFM_NUMBERINGSTYLE, wNumberingStyle);
983c2c66affSColin Finck CHECK_FIELD(PFM_NUMBERINGTAB, wNumberingTab);
984c2c66affSColin Finck CHECK_FIELD(PFM_BORDER, wBorderSpace);
985c2c66affSColin Finck CHECK_FIELD(PFM_BORDER, wBorderWidth);
986c2c66affSColin Finck CHECK_FIELD(PFM_BORDER, wBorders);
987c2c66affSColin Finck }
988c2c66affSColin Finck #undef CHECK_FIELD
989c2c66affSColin Finck }
990c2c66affSColin Finck }
991c2c66affSColin Finck
ME_SetDefaultParaFormat(ME_TextEditor * editor,PARAFORMAT2 * pFmt)992c2c66affSColin Finck void ME_SetDefaultParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt)
993c2c66affSColin Finck {
994c2c66affSColin Finck const PARAFORMAT2 *host_fmt;
995c2c66affSColin Finck HRESULT hr;
996c2c66affSColin Finck
997c2c66affSColin Finck ZeroMemory(pFmt, sizeof(PARAFORMAT2));
998c2c66affSColin Finck pFmt->cbSize = sizeof(PARAFORMAT2);
999c2c66affSColin Finck pFmt->dwMask = PFM_ALL2;
1000c2c66affSColin Finck pFmt->wAlignment = PFA_LEFT;
1001c2c66affSColin Finck pFmt->sStyle = -1;
1002c2c66affSColin Finck pFmt->bOutlineLevel = TRUE;
1003c2c66affSColin Finck
1004c2c66affSColin Finck hr = ITextHost_TxGetParaFormat( editor->texthost, (const PARAFORMAT **)&host_fmt );
1005c2c66affSColin Finck if (SUCCEEDED(hr))
1006c2c66affSColin Finck {
1007c2c66affSColin Finck /* Just use the alignment for now */
1008c2c66affSColin Finck if (host_fmt->dwMask & PFM_ALIGNMENT)
1009c2c66affSColin Finck pFmt->wAlignment = host_fmt->wAlignment;
1010c2c66affSColin Finck ITextHost_OnTxParaFormatChange( editor->texthost, (PARAFORMAT *)pFmt );
1011c2c66affSColin Finck }
1012c2c66affSColin Finck }
1013