2 * RichEdit - functions working on paragraphs of text (diParagraph).
4 * Copyright 2004 by Krzysztof Foltman
5 * Copyright 2006 by Phil Krylov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 WINE_DEFAULT_DEBUG_CHANNEL(richedit
);
26 static const WCHAR wszParagraphSign
[] = {0xB6, 0};
28 void ME_MakeFirstParagraph(ME_TextEditor
*editor
)
34 ME_TextBuffer
*text
= editor
->pBuffer
;
35 ME_DisplayItem
*para
= ME_MakeDI(diParagraph
);
39 ME_InitContext(&c
, editor
, GetDC(editor
->hWnd
));
41 hf
= GetStockObject(SYSTEM_FONT
);
43 GetObjectW(hf
, sizeof(LOGFONTW
), &lf
);
44 ZeroMemory(&cf
, sizeof(cf
));
45 cf
.cbSize
= sizeof(cf
);
46 cf
.dwMask
= CFM_BACKCOLOR
|CFM_COLOR
|CFM_FACE
|CFM_SIZE
|CFM_CHARSET
;
47 cf
.dwMask
|= CFM_ALLCAPS
|CFM_BOLD
|CFM_DISABLED
|CFM_EMBOSS
|CFM_HIDDEN
;
48 cf
.dwMask
|= CFM_IMPRINT
|CFM_ITALIC
|CFM_LINK
|CFM_OUTLINE
|CFM_PROTECTED
;
49 cf
.dwMask
|= CFM_REVISED
|CFM_SHADOW
|CFM_SMALLCAPS
|CFM_STRIKEOUT
;
50 cf
.dwMask
|= CFM_SUBSCRIPT
|CFM_UNDERLINETYPE
|CFM_WEIGHT
;
52 cf
.dwEffects
= CFE_AUTOCOLOR
| CFE_AUTOBACKCOLOR
;
53 lstrcpyW(cf
.szFaceName
, lf
.lfFaceName
);
54 /* Convert system font height from logical units to twips for cf.yHeight */
55 cf
.yHeight
= (lf
.lfHeight
* 72 * 1440) / (c
.dpi
.cy
* c
.dpi
.cy
);
56 if (lf
.lfWeight
> FW_NORMAL
) cf
.dwEffects
|= CFE_BOLD
;
57 cf
.wWeight
= lf
.lfWeight
;
58 if (lf
.lfItalic
) cf
.dwEffects
|= CFE_ITALIC
;
59 cf
.bUnderlineType
= (lf
.lfUnderline
) ? CFU_CF1UNDERLINE
: CFU_UNDERLINENONE
;
60 if (lf
.lfStrikeOut
) cf
.dwEffects
|= CFE_STRIKEOUT
;
61 cf
.bPitchAndFamily
= lf
.lfPitchAndFamily
;
62 cf
.bCharSet
= lf
.lfCharSet
;
64 style
= ME_MakeStyle(&cf
);
65 text
->pDefaultStyle
= style
;
67 run
= ME_MakeRun(style
, ME_MakeString(wszParagraphSign
), MERF_ENDPARA
);
68 run
->member
.run
.nCharOfs
= 0;
69 run
->member
.run
.nCR
= 1;
70 run
->member
.run
.nLF
= (editor
->bEmulateVersion10
) ? 1 : 0;
72 ME_InsertBefore(text
->pLast
, para
);
73 ME_InsertBefore(text
->pLast
, run
);
74 para
->member
.para
.prev_para
= text
->pFirst
;
75 para
->member
.para
.next_para
= text
->pLast
;
76 text
->pFirst
->member
.para
.next_para
= para
;
77 text
->pLast
->member
.para
.prev_para
= para
;
79 text
->pLast
->member
.para
.nCharOfs
= 1;
81 ME_DestroyContext(&c
, editor
->hWnd
);
84 void ME_MarkAllForWrapping(ME_TextEditor
*editor
)
86 ME_MarkForWrapping(editor
, editor
->pBuffer
->pFirst
->member
.para
.next_para
, editor
->pBuffer
->pLast
);
89 void ME_MarkForWrapping(ME_TextEditor
*editor
, ME_DisplayItem
*first
, const ME_DisplayItem
*last
)
93 first
->member
.para
.nFlags
|= MEPF_REWRAP
;
94 first
= first
->member
.para
.next_para
;
98 void ME_MarkForPainting(ME_TextEditor
*editor
, ME_DisplayItem
*first
, const ME_DisplayItem
*last
)
100 while(first
!= last
&& first
)
102 first
->member
.para
.nFlags
|= MEPF_REPAINT
;
103 first
= first
->member
.para
.next_para
;
107 static void ME_UpdateTableFlags(ME_DisplayItem
*para
)
109 para
->member
.para
.pFmt
->dwMask
|= PFM_TABLE
|PFM_TABLEROWDELIMITER
;
110 if (para
->member
.para
.pCell
) {
111 para
->member
.para
.nFlags
|= MEPF_CELL
;
113 para
->member
.para
.nFlags
&= ~MEPF_CELL
;
115 if (para
->member
.para
.nFlags
& MEPF_ROWEND
) {
116 para
->member
.para
.pFmt
->wEffects
|= PFE_TABLEROWDELIMITER
;
118 para
->member
.para
.pFmt
->wEffects
&= ~PFE_TABLEROWDELIMITER
;
120 if (para
->member
.para
.nFlags
& (MEPF_ROWSTART
|MEPF_CELL
|MEPF_ROWEND
))
121 para
->member
.para
.pFmt
->wEffects
|= PFE_TABLE
;
123 para
->member
.para
.pFmt
->wEffects
&= ~PFE_TABLE
;
126 /* split paragraph at the beginning of the run */
127 ME_DisplayItem
*ME_SplitParagraph(ME_TextEditor
*editor
, ME_DisplayItem
*run
,
128 ME_Style
*style
, int numCR
, int numLF
,
131 ME_DisplayItem
*next_para
= NULL
;
132 ME_DisplayItem
*run_para
= NULL
;
133 ME_DisplayItem
*new_para
= ME_MakeDI(diParagraph
);
134 ME_DisplayItem
*end_run
;
135 ME_UndoItem
*undo
= NULL
;
138 int end_len
= numCR
+ numLF
;
139 int run_flags
= MERF_ENDPARA
;
140 if (!editor
->bEmulateVersion10
) { /* v4.1 */
141 /* At most 1 of MEPF_CELL, MEPF_ROWSTART, or MEPF_ROWEND should be set. */
142 assert(!(paraFlags
& ~(MEPF_CELL
|MEPF_ROWSTART
|MEPF_ROWEND
)));
143 assert(!(paraFlags
& (paraFlags
-1)));
144 if (paraFlags
== MEPF_CELL
)
145 run_flags
|= MERF_ENDCELL
;
146 else if (paraFlags
== MEPF_ROWSTART
)
147 run_flags
|= MERF_TABLESTART
|MERF_HIDDEN
;
148 } else { /* v1.0 - v3.0 */
149 assert(!(paraFlags
& (MEPF_CELL
|MEPF_ROWSTART
|MEPF_ROWEND
)));
151 end_run
= ME_MakeRun(style
,ME_MakeString(wszParagraphSign
), run_flags
);
153 assert(run
->type
== diRun
);
155 end_run
->member
.run
.nCR
= numCR
;
156 end_run
->member
.run
.nLF
= numLF
;
157 run_para
= ME_GetParagraph(run
);
158 assert(run_para
->member
.para
.pFmt
->cbSize
== sizeof(PARAFORMAT2
));
160 ofs
= end_run
->member
.run
.nCharOfs
= run
->member
.run
.nCharOfs
;
161 next_para
= run_para
->member
.para
.next_para
;
162 assert(next_para
== ME_FindItemFwd(run_para
, diParagraphOrEnd
));
164 undo
= ME_AddUndoItem(editor
, diUndoJoinParagraphs
, NULL
);
166 undo
->nStart
= run_para
->member
.para
.nCharOfs
+ ofs
;
168 /* the new paragraph will have a different starting offset, so let's update its runs */
170 while(pp
->type
== diRun
) {
171 pp
->member
.run
.nCharOfs
-= ofs
;
172 pp
= ME_FindItemFwd(pp
, diRunOrParagraphOrEnd
);
174 new_para
->member
.para
.nCharOfs
= ME_GetParagraph(run
)->member
.para
.nCharOfs
+ofs
;
175 new_para
->member
.para
.nCharOfs
+= end_len
;
176 new_para
->member
.para
.nFlags
= MEPF_REWRAP
;
178 /* FIXME initialize format style and call ME_SetParaFormat blah blah */
179 *new_para
->member
.para
.pFmt
= *run_para
->member
.para
.pFmt
;
180 new_para
->member
.para
.border
= run_para
->member
.para
.border
;
182 /* insert paragraph into paragraph double linked list */
183 new_para
->member
.para
.prev_para
= run_para
;
184 new_para
->member
.para
.next_para
= next_para
;
185 run_para
->member
.para
.next_para
= new_para
;
186 next_para
->member
.para
.prev_para
= new_para
;
188 /* insert end run of the old paragraph, and new paragraph, into DI double linked list */
189 ME_InsertBefore(run
, new_para
);
190 ME_InsertBefore(new_para
, end_run
);
192 if (!editor
->bEmulateVersion10
) { /* v4.1 */
193 if (paraFlags
& (MEPF_ROWSTART
|MEPF_CELL
))
195 ME_DisplayItem
*cell
= ME_MakeDI(diCell
);
196 ME_InsertBefore(new_para
, cell
);
197 new_para
->member
.para
.pCell
= cell
;
198 cell
->member
.cell
.next_cell
= NULL
;
199 if (paraFlags
& MEPF_ROWSTART
)
201 run_para
->member
.para
.nFlags
|= MEPF_ROWSTART
;
202 cell
->member
.cell
.prev_cell
= NULL
;
203 cell
->member
.cell
.parent_cell
= run_para
->member
.para
.pCell
;
204 if (run_para
->member
.para
.pCell
)
205 cell
->member
.cell
.nNestingLevel
= run_para
->member
.para
.pCell
->member
.cell
.nNestingLevel
+ 1;
207 cell
->member
.cell
.nNestingLevel
= 1;
209 cell
->member
.cell
.prev_cell
= run_para
->member
.para
.pCell
;
210 assert(cell
->member
.cell
.prev_cell
);
211 cell
->member
.cell
.prev_cell
->member
.cell
.next_cell
= cell
;
212 assert(run_para
->member
.para
.nFlags
& MEPF_CELL
);
213 assert(!(run_para
->member
.para
.nFlags
& MEPF_ROWSTART
));
214 cell
->member
.cell
.nNestingLevel
= cell
->member
.cell
.prev_cell
->member
.cell
.nNestingLevel
;
215 cell
->member
.cell
.parent_cell
= cell
->member
.cell
.prev_cell
->member
.cell
.parent_cell
;
217 } else if (paraFlags
& MEPF_ROWEND
) {
218 run_para
->member
.para
.nFlags
|= MEPF_ROWEND
;
219 run_para
->member
.para
.pCell
= run_para
->member
.para
.pCell
->member
.cell
.parent_cell
;
220 new_para
->member
.para
.pCell
= run_para
->member
.para
.pCell
;
221 assert(run_para
->member
.para
.prev_para
->member
.para
.nFlags
& MEPF_CELL
);
222 assert(!(run_para
->member
.para
.prev_para
->member
.para
.nFlags
& MEPF_ROWSTART
));
223 if (new_para
->member
.para
.pCell
!= new_para
->member
.para
.next_para
->member
.para
.pCell
224 && new_para
->member
.para
.next_para
->member
.para
.pCell
225 && !new_para
->member
.para
.next_para
->member
.para
.pCell
->member
.cell
.prev_cell
)
227 /* Row starts just after the row that was ended. */
228 new_para
->member
.para
.nFlags
|= MEPF_ROWSTART
;
231 new_para
->member
.para
.pCell
= run_para
->member
.para
.pCell
;
233 ME_UpdateTableFlags(run_para
);
234 ME_UpdateTableFlags(new_para
);
237 /* force rewrap of the */
238 run_para
->member
.para
.prev_para
->member
.para
.nFlags
|= MEPF_REWRAP
;
239 new_para
->member
.para
.prev_para
->member
.para
.nFlags
|= MEPF_REWRAP
;
241 /* we've added the end run, so we need to modify nCharOfs in the next paragraphs */
242 ME_PropagateCharOffset(next_para
, end_len
);
243 editor
->nParagraphs
++;
248 /* join tp with tp->member.para.next_para, keeping tp's style; this
249 * is consistent with the original */
250 ME_DisplayItem
*ME_JoinParagraphs(ME_TextEditor
*editor
, ME_DisplayItem
*tp
,
251 BOOL keepFirstParaFormat
)
253 ME_DisplayItem
*pNext
, *pFirstRunInNext
, *pRun
, *pTmp
;
255 ME_UndoItem
*undo
= NULL
;
258 assert(tp
->type
== diParagraph
);
259 assert(tp
->member
.para
.next_para
);
260 assert(tp
->member
.para
.next_para
->type
== diParagraph
);
262 pNext
= tp
->member
.para
.next_para
;
264 /* Need to locate end-of-paragraph run here, in order to know end_len */
265 pRun
= ME_FindItemBack(pNext
, diRunOrParagraph
);
268 assert(pRun
->type
== diRun
);
269 assert(pRun
->member
.run
.nFlags
& MERF_ENDPARA
);
271 end_len
= pRun
->member
.run
.nCR
+ pRun
->member
.run
.nLF
;
274 /* null char format operation to store the original char format for the ENDPARA run */
276 ME_InitCharFormat2W(&fmt
);
277 ME_SetCharFormat(editor
, pNext
->member
.para
.nCharOfs
- end_len
, end_len
, &fmt
);
279 undo
= ME_AddUndoItem(editor
, diUndoSplitParagraph
, pNext
);
282 undo
->nStart
= pNext
->member
.para
.nCharOfs
- end_len
;
283 undo
->nCR
= pRun
->member
.run
.nCR
;
284 undo
->nLF
= pRun
->member
.run
.nLF
;
286 if (!keepFirstParaFormat
)
288 ME_AddUndoItem(editor
, diUndoSetParagraphFormat
, tp
);
289 *tp
->member
.para
.pFmt
= *pNext
->member
.para
.pFmt
;
290 tp
->member
.para
.border
= pNext
->member
.para
.border
;
293 if (!editor
->bEmulateVersion10
) { /* v4.1 */
294 /* Table cell/row properties are always moved over from the removed para. */
295 tp
->member
.para
.nFlags
= pNext
->member
.para
.nFlags
;
296 tp
->member
.para
.pCell
= pNext
->member
.para
.pCell
;
298 /* Remove cell boundary if it is between the end paragraph run and the next
299 * paragraph display item. */
301 while (pTmp
!= pNext
) {
302 if (pTmp
->type
== diCell
)
304 ME_Cell
*pCell
= &pTmp
->member
.cell
;
307 assert(!(undo
->di
.member
.para
.nFlags
& MEPF_ROWEND
));
308 if (!(undo
->di
.member
.para
.nFlags
& MEPF_ROWSTART
))
309 undo
->di
.member
.para
.nFlags
|= MEPF_CELL
;
310 undo
->di
.member
.para
.pCell
= ALLOC_OBJ(ME_DisplayItem
);
311 *undo
->di
.member
.para
.pCell
= *pTmp
;
312 undo
->di
.member
.para
.pCell
->next
= NULL
;
313 undo
->di
.member
.para
.pCell
->prev
= NULL
;
314 undo
->di
.member
.para
.pCell
->member
.cell
.next_cell
= NULL
;
315 undo
->di
.member
.para
.pCell
->member
.cell
.prev_cell
= NULL
;
318 if (pCell
->prev_cell
)
319 pCell
->prev_cell
->member
.cell
.next_cell
= pCell
->next_cell
;
320 if (pCell
->next_cell
)
321 pCell
->next_cell
->member
.cell
.prev_cell
= pCell
->prev_cell
;
322 ME_DestroyDisplayItem(pTmp
);
329 shift
= pNext
->member
.para
.nCharOfs
- tp
->member
.para
.nCharOfs
- end_len
;
331 pFirstRunInNext
= ME_FindItemFwd(pNext
, diRunOrParagraph
);
333 assert(pFirstRunInNext
->type
== diRun
);
335 /* if some cursor points at end of paragraph, make it point to the first
336 run of the next joined paragraph */
337 for (i
=0; i
<editor
->nCursors
; i
++) {
338 if (editor
->pCursors
[i
].pRun
== pRun
) {
339 editor
->pCursors
[i
].pRun
= pFirstRunInNext
;
340 editor
->pCursors
[i
].nOffset
= 0;
346 pTmp
= ME_FindItemFwd(pTmp
, diRunOrParagraphOrEnd
);
347 if (pTmp
->type
!= diRun
)
349 TRACE("shifting \"%s\" by %d (previous %d)\n", debugstr_w(pTmp
->member
.run
.strText
->szData
), shift
, pTmp
->member
.run
.nCharOfs
);
350 pTmp
->member
.run
.nCharOfs
+= shift
;
354 ME_DestroyDisplayItem(pRun
);
356 if (editor
->pLastSelStartPara
== pNext
)
357 editor
->pLastSelStartPara
= tp
;
358 if (editor
->pLastSelEndPara
== pNext
)
359 editor
->pLastSelEndPara
= tp
;
361 tp
->member
.para
.next_para
= pNext
->member
.para
.next_para
;
362 pNext
->member
.para
.next_para
->member
.para
.prev_para
= tp
;
364 ME_DestroyDisplayItem(pNext
);
366 ME_PropagateCharOffset(tp
->member
.para
.next_para
, -end_len
);
368 ME_CheckCharOffsets(editor
);
370 editor
->nParagraphs
--;
371 tp
->member
.para
.nFlags
|= MEPF_REWRAP
;
375 ME_DisplayItem
*ME_GetParagraph(ME_DisplayItem
*item
) {
376 return ME_FindItemBackOrHere(item
, diParagraph
);
379 void ME_DumpParaStyleToBuf(const PARAFORMAT2
*pFmt
, char buf
[2048])
384 #define DUMP(mask, name, fmt, field) \
385 if (pFmt->dwMask & (mask)) p += sprintf(p, "%-22s" fmt "\n", name, pFmt->field); \
386 else p += sprintf(p, "%-22sN/A\n", name);
388 /* we take for granted that PFE_xxx is the hiword of the corresponding PFM_xxx */
389 #define DUMP_EFFECT(mask, name) \
390 p += sprintf(p, "%-22s%s\n", name, (pFmt->dwMask & (mask)) ? ((pFmt->wEffects & ((mask) >> 8)) ? "yes" : "no") : "N/A");
392 DUMP(PFM_NUMBERING
, "Numbering:", "%u", wNumbering
);
393 DUMP_EFFECT(PFM_DONOTHYPHEN
, "Disable auto-hyphen:");
394 DUMP_EFFECT(PFM_KEEP
, "No page break in para:");
395 DUMP_EFFECT(PFM_KEEPNEXT
, "No page break in para & next:");
396 DUMP_EFFECT(PFM_NOLINENUMBER
, "No line number:");
397 DUMP_EFFECT(PFM_NOWIDOWCONTROL
, "No widow & orphan:");
398 DUMP_EFFECT(PFM_PAGEBREAKBEFORE
, "Page break before:");
399 DUMP_EFFECT(PFM_RTLPARA
, "RTL para:");
400 DUMP_EFFECT(PFM_SIDEBYSIDE
, "Side by side:");
401 DUMP_EFFECT(PFM_TABLE
, "Table:");
402 DUMP(PFM_OFFSETINDENT
, "Offset indent:", "%d", dxStartIndent
);
403 DUMP(PFM_STARTINDENT
, "Start indent:", "%d", dxStartIndent
);
404 DUMP(PFM_RIGHTINDENT
, "Right indent:", "%d", dxRightIndent
);
405 DUMP(PFM_OFFSET
, "Offset:", "%d", dxOffset
);
406 if (pFmt
->dwMask
& PFM_ALIGNMENT
) {
407 switch (pFmt
->wAlignment
) {
408 case PFA_LEFT
: p
+= sprintf(p
, "Alignment: left\n"); break;
409 case PFA_RIGHT
: p
+= sprintf(p
, "Alignment: right\n"); break;
410 case PFA_CENTER
: p
+= sprintf(p
, "Alignment: center\n"); break;
411 case PFA_JUSTIFY
: p
+= sprintf(p
, "Alignment: justify\n"); break;
412 default : p
+= sprintf(p
, "Alignment: incorrect %d\n", pFmt
->wAlignment
); break;
415 else p
+= sprintf(p
, "Alignment: N/A\n");
416 DUMP(PFM_TABSTOPS
, "Tab Stops:", "%d", cTabCount
);
417 if (pFmt
->dwMask
& PFM_TABSTOPS
) {
419 p
+= sprintf(p
, "\t");
420 for (i
= 0; i
< pFmt
->cTabCount
; i
++) p
+= sprintf(p
, "%x ", pFmt
->rgxTabs
[i
]);
421 p
+= sprintf(p
, "\n");
423 DUMP(PFM_SPACEBEFORE
, "Space Before:", "%d", dySpaceBefore
);
424 DUMP(PFM_SPACEAFTER
, "Space After:", "%d", dySpaceAfter
);
425 DUMP(PFM_LINESPACING
, "Line spacing:", "%d", dyLineSpacing
);
426 DUMP(PFM_STYLE
, "Text style:", "%d", sStyle
);
427 DUMP(PFM_LINESPACING
, "Line spacing rule:", "%u", bLineSpacingRule
);
428 /* bOutlineLevel should be 0 */
429 DUMP(PFM_SHADING
, "Shading Weigth:", "%u", wShadingWeight
);
430 DUMP(PFM_SHADING
, "Shading Style:", "%u", wShadingStyle
);
431 DUMP(PFM_NUMBERINGSTART
, "Numbering Start:", "%u", wNumberingStart
);
432 DUMP(PFM_NUMBERINGSTYLE
, "Numbering Style:", "0x%x", wNumberingStyle
);
433 DUMP(PFM_NUMBERINGTAB
, "Numbering Tab:", "%u", wNumberingStyle
);
434 DUMP(PFM_BORDER
, "Border Space:", "%u", wBorderSpace
);
435 DUMP(PFM_BORDER
, "Border Width:", "%u", wBorderWidth
);
436 DUMP(PFM_BORDER
, "Borders:", "%u", wBorders
);
442 BOOL
ME_SetParaFormat(ME_TextEditor
*editor
, ME_DisplayItem
*para
, const PARAFORMAT2
*pFmt
)
445 assert(sizeof(*para
->member
.para
.pFmt
) == sizeof(PARAFORMAT2
));
446 ME_AddUndoItem(editor
, diUndoSetParagraphFormat
, para
);
448 copy
= *para
->member
.para
.pFmt
;
450 #define COPY_FIELD(m, f) \
451 if (pFmt->dwMask & (m)) { \
452 para->member.para.pFmt->dwMask |= m; \
453 para->member.para.pFmt->f = pFmt->f; \
456 COPY_FIELD(PFM_NUMBERING
, wNumbering
);
457 #define EFFECTS_MASK (PFM_RTLPARA|PFM_KEEP|PFM_KEEPNEXT|PFM_PAGEBREAKBEFORE| \
458 PFM_NOLINENUMBER|PFM_NOWIDOWCONTROL|PFM_DONOTHYPHEN|PFM_SIDEBYSIDE| \
460 /* we take for granted that PFE_xxx is the hiword of the corresponding PFM_xxx */
461 if (pFmt
->dwMask
& EFFECTS_MASK
) {
462 para
->member
.para
.pFmt
->dwMask
|= pFmt
->dwMask
& EFFECTS_MASK
;
463 para
->member
.para
.pFmt
->wEffects
&= ~HIWORD(pFmt
->dwMask
);
464 para
->member
.para
.pFmt
->wEffects
|= pFmt
->wEffects
& HIWORD(pFmt
->dwMask
);
468 COPY_FIELD(PFM_STARTINDENT
, dxStartIndent
);
469 if (pFmt
->dwMask
& PFM_OFFSETINDENT
)
470 para
->member
.para
.pFmt
->dxStartIndent
+= pFmt
->dxStartIndent
;
471 COPY_FIELD(PFM_RIGHTINDENT
, dxRightIndent
);
472 COPY_FIELD(PFM_OFFSET
, dxOffset
);
473 COPY_FIELD(PFM_ALIGNMENT
, wAlignment
);
475 if (pFmt
->dwMask
& PFM_TABSTOPS
)
477 para
->member
.para
.pFmt
->cTabCount
= pFmt
->cTabCount
;
478 memcpy(para
->member
.para
.pFmt
->rgxTabs
, pFmt
->rgxTabs
, pFmt
->cTabCount
*sizeof(LONG
));
480 COPY_FIELD(PFM_SPACEBEFORE
, dySpaceBefore
);
481 COPY_FIELD(PFM_SPACEAFTER
, dySpaceAfter
);
482 COPY_FIELD(PFM_LINESPACING
, dyLineSpacing
);
483 COPY_FIELD(PFM_STYLE
, sStyle
);
484 COPY_FIELD(PFM_LINESPACING
, bLineSpacingRule
);
485 COPY_FIELD(PFM_SHADING
, wShadingWeight
);
486 COPY_FIELD(PFM_SHADING
, wShadingStyle
);
487 COPY_FIELD(PFM_NUMBERINGSTART
, wNumberingStart
);
488 COPY_FIELD(PFM_NUMBERINGSTYLE
, wNumberingStyle
);
489 COPY_FIELD(PFM_NUMBERINGTAB
, wNumberingTab
);
490 COPY_FIELD(PFM_BORDER
, wBorderSpace
);
491 COPY_FIELD(PFM_BORDER
, wBorderWidth
);
492 COPY_FIELD(PFM_BORDER
, wBorders
);
494 para
->member
.para
.pFmt
->dwMask
|= pFmt
->dwMask
;
497 if (memcmp(©
, para
->member
.para
.pFmt
, sizeof(PARAFORMAT2
)))
498 para
->member
.para
.nFlags
|= MEPF_REWRAP
;
505 ME_GetSelectionParas(ME_TextEditor
*editor
, ME_DisplayItem
**para
, ME_DisplayItem
**para_end
)
507 ME_Cursor
*pEndCursor
= &editor
->pCursors
[1];
509 *para
= ME_GetParagraph(editor
->pCursors
[0].pRun
);
510 *para_end
= ME_GetParagraph(editor
->pCursors
[1].pRun
);
511 if ((*para_end
)->member
.para
.nCharOfs
< (*para
)->member
.para
.nCharOfs
) {
512 ME_DisplayItem
*tmp
= *para
;
516 pEndCursor
= &editor
->pCursors
[0];
519 /* selection consists of chars from nFrom up to nTo-1 */
520 if ((*para_end
)->member
.para
.nCharOfs
> (*para
)->member
.para
.nCharOfs
) {
521 if (!pEndCursor
->nOffset
) {
522 *para_end
= ME_GetParagraph(ME_FindItemBack(pEndCursor
->pRun
, diRun
));
528 BOOL
ME_SetSelectionParaFormat(ME_TextEditor
*editor
, const PARAFORMAT2
*pFmt
)
530 ME_DisplayItem
*para
, *para_end
;
532 ME_GetSelectionParas(editor
, ¶
, ¶_end
);
535 ME_SetParaFormat(editor
, para
, pFmt
);
536 if (para
== para_end
)
538 para
= para
->member
.para
.next_para
;
544 void ME_GetParaFormat(ME_TextEditor
*editor
, const ME_DisplayItem
*para
, PARAFORMAT2
*pFmt
)
546 if (pFmt
->cbSize
>= sizeof(PARAFORMAT2
))
548 *pFmt
= *para
->member
.para
.pFmt
;
551 CopyMemory(pFmt
, para
->member
.para
.pFmt
, pFmt
->cbSize
);
554 void ME_GetSelectionParaFormat(ME_TextEditor
*editor
, PARAFORMAT2
*pFmt
)
556 ME_DisplayItem
*para
, *para_end
;
559 ME_GetSelectionParas(editor
, ¶
, ¶_end
);
561 ME_GetParaFormat(editor
, para
, pFmt
);
562 if (para
== para_end
) return;
564 /* Invalidate values that change across the selected paragraphs. */
566 ZeroMemory(&tmp
, sizeof(tmp
));
567 tmp
.cbSize
= sizeof(tmp
);
568 ME_GetParaFormat(editor
, para
, &tmp
);
570 #define CHECK_FIELD(m, f) \
571 if (pFmt->f != tmp.f) pFmt->dwMask &= ~(m);
573 pFmt
->dwMask
&= ~((pFmt
->wEffects
^ tmp
.wEffects
) << 16);
574 CHECK_FIELD(PFM_NUMBERING
, wNumbering
);
575 assert(tmp
.dwMask
& PFM_ALIGNMENT
);
576 CHECK_FIELD(PFM_NUMBERING
, wNumbering
);
577 assert(tmp
.dwMask
& PFM_STARTINDENT
);
578 CHECK_FIELD(PFM_STARTINDENT
, dxStartIndent
);
579 assert(tmp
.dwMask
& PFM_RIGHTINDENT
);
580 CHECK_FIELD(PFM_RIGHTINDENT
, dxRightIndent
);
581 assert(tmp
.dwMask
& PFM_OFFSET
);
582 CHECK_FIELD(PFM_OFFSET
, dxOffset
);
583 CHECK_FIELD(PFM_ALIGNMENT
, wAlignment
);
585 assert(tmp
.dwMask
& PFM_TABSTOPS
);
586 if (pFmt
->dwMask
& PFM_TABSTOPS
) {
587 if (pFmt
->cTabCount
!= tmp
.cTabCount
||
588 memcmp(pFmt
->rgxTabs
, tmp
.rgxTabs
, tmp
.cTabCount
*sizeof(int)))
589 pFmt
->dwMask
&= ~PFM_TABSTOPS
;
592 CHECK_FIELD(PFM_SPACEBEFORE
, dySpaceBefore
);
593 CHECK_FIELD(PFM_SPACEAFTER
, dySpaceAfter
);
594 CHECK_FIELD(PFM_LINESPACING
, dyLineSpacing
);
595 CHECK_FIELD(PFM_STYLE
, sStyle
);
596 CHECK_FIELD(PFM_SPACEAFTER
, bLineSpacingRule
);
597 CHECK_FIELD(PFM_SHADING
, wShadingWeight
);
598 CHECK_FIELD(PFM_SHADING
, wShadingStyle
);
599 CHECK_FIELD(PFM_NUMBERINGSTART
, wNumberingStart
);
600 CHECK_FIELD(PFM_NUMBERINGSTYLE
, wNumberingStyle
);
601 CHECK_FIELD(PFM_NUMBERINGTAB
, wNumberingTab
);
602 CHECK_FIELD(PFM_BORDER
, wBorderSpace
);
603 CHECK_FIELD(PFM_BORDER
, wBorderWidth
);
604 CHECK_FIELD(PFM_BORDER
, wBorders
);
608 if (para
== para_end
)
610 para
= para
->member
.para
.next_para
;
614 void ME_SetDefaultParaFormat(PARAFORMAT2
*pFmt
)
616 ZeroMemory(pFmt
, sizeof(PARAFORMAT2
));
617 pFmt
->cbSize
= sizeof(PARAFORMAT2
);
618 pFmt
->dwMask
= PFM_ALL2
;
619 pFmt
->wAlignment
= PFA_LEFT
;
621 pFmt
->bOutlineLevel
= TRUE
;