1 #include "RichEdit.h"
2 
3 namespace Upp {
4 
GetNumbering()5 RichPara::NumberFormat ParaFormatting::GetNumbering()
6 {
7 	RichPara::NumberFormat f;
8 	f.before_number = ~before_number;
9 	f.after_number = ~after_number;
10 	f.reset_number = ~reset_number;
11 	for(int i = 0; i < 8; i++)
12 		f.number[i] = Nvl((int)~n[i]);
13 	return f;
14 }
15 
IsNumbering()16 bool ParaFormatting::IsNumbering()
17 {
18 	if(!IsNull(before_number) || !IsNull(after_number) || reset_number)
19 		return true;
20 	for(int i = 0; i < 8; i++)
21 		if(!IsNull(n[i]))
22 		   return true;
23 	return false;
24 }
25 
EnableNumbering()26 void ParaFormatting::EnableNumbering()
27 {
28 	bool b = !IsNull(bullet) && !(int)~bullet;
29 	before_number.Enable(b);
30 	after_number.Enable(b);
31 	for(int i = 0; i < 8; i++)
32 		n[i].Enable(b);
33 }
34 
ComputeIndent()35 int  ParaFormatting::ComputeIndent()
36 {
37 	if(!IsNull(bullet) && (int)~bullet)
38 		return 150;
39 	if(IsNumbering()) {
40 		RichPara::NumberFormat f = GetNumbering();
41 		RichPara::Number n;
42 		static byte n0[] = { 0, 37, 38, 48, 48, 37, 37 };
43 		static byte n1[] = { 0, 17, 18, 12, 12, 17, 17 };
44 		if(f.number[0] && f.number[0] < 8)
45 			n.n[0] = n0[f.number[0]];
46 		if(f.number[1] && f.number[1] < 8)
47 			n.n[1] = n1[f.number[1]];
48 		for(int i = 2; i < 8; i++) {
49 			static byte nn[] = { 0,  7,  8,  1,  1,  7,  7 };
50 			if(f.number[i] && f.number[i] < 8)
51 				n.n[i] = nn[f.number[i]];
52 		}
53 		String s = n.AsText(f);
54 		s.Cat(' ');
55 		return GetTextSize(s, font).cx;
56 	}
57 	return 0;
58 }
59 
SetupIndent()60 void ParaFormatting::SetupIndent()
61 {
62 	EnableNumbering();
63 	if(indent.IsModified() || keepindent) return;
64 	indent <<= ComputeIndent();
65 	indent.ClearModify();
66 }
67 
EditHdrFtr()68 void ParaFormatting::EditHdrFtr()
69 {
70 	if(EditRichHeaderFooter(header_qtf, footer_qtf))
71 		modified = true;
72 }
73 
NewHdrFtr()74 void ParaFormatting::NewHdrFtr()
75 {
76 	SyncHdrFtr();
77 	if(newhdrftr)
78 		EditHdrFtr();
79 }
80 
SyncHdrFtr()81 void ParaFormatting::SyncHdrFtr()
82 {
83 	hdrftr.Enable(newhdrftr && newhdrftr.IsEnabled());
84 }
85 
Set(int unit,const RichText::FormatInfo & formatinfo,bool baselevel)86 void ParaFormatting::Set(int unit, const RichText::FormatInfo& formatinfo, bool baselevel)
87 {
88 	newhdrftr.Enable(baselevel);
89 	hdrftr.Enable(baselevel);
90 	font = formatinfo;
91 	ruler.Set(unit, RichText::RULER & formatinfo.paravalid ? formatinfo.ruler : Null);
92 	before.Set(unit, RichText::BEFORE & formatinfo.paravalid ? formatinfo.before : Null);
93 	lm.Set(unit, RichText::LM & formatinfo.paravalid ? formatinfo.lm : Null);
94 	indent.Set(unit, RichText::INDENT & formatinfo.paravalid ? formatinfo.indent : Null);
95 	rm.Set(unit, RichText::RM & formatinfo.paravalid ? formatinfo.rm : Null);
96 	after.Set(unit, RichText::AFTER & formatinfo.paravalid ? formatinfo.after : Null);
97 	if(RichText::ALIGN & formatinfo.paravalid)
98 		align <<= formatinfo.align == ALIGN_LEFT    ? 0 :
99 		          formatinfo.align == ALIGN_CENTER  ? 1 :
100 		          formatinfo.align == ALIGN_RIGHT   ? 2 :
101 		                                            3;
102 	if(RichText::NEWHDRFTR & formatinfo.paravalid) {
103 		newhdrftr = formatinfo.newhdrftr;
104 		header_qtf = formatinfo.header_qtf;
105 		footer_qtf = formatinfo.footer_qtf;
106 	}
107 	else {
108 		newhdrftr = Null;
109 		newhdrftr.ThreeState();
110 	}
111 	if(RichText::NEWPAGE & formatinfo.paravalid)
112 		page = formatinfo.newpage;
113 	else {
114 		page = Null;
115 		page.ThreeState();
116 	}
117 	if(RichText::KEEP & formatinfo.paravalid)
118 		keep = formatinfo.keep;
119 	else {
120 		keep = Null;
121 		keep.ThreeState();
122 	}
123 	if(RichText::KEEPNEXT & formatinfo.paravalid)
124 		keepnext = formatinfo.keepnext;
125 	else {
126 		keepnext = Null;
127 		keepnext.ThreeState();
128 	}
129 	if(RichText::ORPHAN & formatinfo.paravalid)
130 		orphan = formatinfo.orphan;
131 	else {
132 		orphan = Null;
133 		orphan.ThreeState();
134 	}
135 	if(RichText::RULERINK & formatinfo.paravalid)
136 		rulerink <<= formatinfo.rulerink;
137 	else
138 		rulerink <<= Null;
139 	if(RichText::RULERSTYLE & formatinfo.paravalid)
140 		rulerstyle <<= formatinfo.rulerstyle;
141 	else
142 		rulerstyle <<= Null;
143 	tabpos.SetUnit(unit);
144 	if(RichText::BULLET & formatinfo.paravalid)
145 		bullet <<= formatinfo.bullet;
146 	else
147 		bullet <<= Null;
148 	if(RichText::SPACING & formatinfo.paravalid)
149 		linespacing <<= formatinfo.linespacing;
150 	else
151 		linespacing <<= Null;
152 	if(RichText::NUMBERING & formatinfo.paravalid) {
153 		before_number <<= formatinfo.before_number.ToWString();
154 		after_number <<= formatinfo.after_number.ToWString();
155 		reset_number <<= formatinfo.reset_number;
156 		for(int i = 0; i < 8; i++)
157 			n[i] = formatinfo.number[i];
158 	}
159 	else {
160 		before_number <<= Null;
161 		after_number <<= Null;
162 		reset_number <<= Null;
163 		reset_number.ThreeState();
164 		for(int i = 0; i < 8; i++)
165 			n[i] = Null;
166 	}
167 	tabs.Clear();
168 	if(RichText::TABS & formatinfo.paravalid)
169 		for(int i = 0; i < formatinfo.tab.GetCount(); i++)
170 			tabs.Add(formatinfo.tab[i].pos, formatinfo.tab[i].align, formatinfo.tab[i].fillchar);
171 	tabsize.Set(unit, RichText::TABSIZE & formatinfo.paravalid ? formatinfo.tabsize : Null);
172 	keepindent = formatinfo.indent != ComputeIndent();
173 	SetupIndent();
174 	ClearModify();
175 	SyncHdrFtr();
176 	modified = false;
177 }
178 
Get(RichText::FormatInfo & formatinfo)179 dword ParaFormatting::Get(RichText::FormatInfo& formatinfo)
180 {
181 	dword v = 0;
182 	if(!IsNull(before)) {
183 		formatinfo.before = ~before;
184 		v |= RichText::BEFORE;
185 	}
186 	if(!IsNull(lm)) {
187 		formatinfo.lm = ~lm;
188 		v |= RichText::LM;
189 	}
190 	if(!IsNull(indent)) {
191 		formatinfo.indent = ~indent;
192 		v |= RichText::INDENT;
193 	}
194 	if(!IsNull(rm)) {
195 		formatinfo.rm = ~rm;
196 		v |= RichText::RM;
197 	}
198 	if(!IsNull(after)) {
199 		formatinfo.after = ~after;
200 		v |= RichText::AFTER;
201 	}
202 	if(!IsNull(align)) {
203 		static int sw[] = { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT, ALIGN_JUSTIFY };
204 		formatinfo.align = sw[(int)~align];
205 		v |= RichText::ALIGN;
206 	}
207 	if(!IsNull(page)) {
208 		formatinfo.newpage = page;
209 		v |= RichText::NEWPAGE;
210 	}
211 	if(!IsNull(newhdrftr)) {
212 		formatinfo.newhdrftr = newhdrftr;
213 		v |= RichText::NEWHDRFTR;
214 		if(formatinfo.newhdrftr) {
215 			formatinfo.header_qtf = header_qtf;
216 			formatinfo.footer_qtf = footer_qtf;
217 		}
218 		else
219 			formatinfo.header_qtf = formatinfo.footer_qtf = Null;
220 	}
221 	if(!IsNull(keep)) {
222 		formatinfo.keep = keep;
223 		v |= RichText::KEEP;
224 	}
225 	if(!IsNull(keepnext)) {
226 		formatinfo.keepnext = keepnext;
227 		v |= RichText::KEEPNEXT;
228 	}
229 	if(!IsNull(orphan)) {
230 		formatinfo.orphan = orphan;
231 		v |= RichText::ORPHAN;
232 	}
233 	if(!IsNull(bullet)) {
234 		formatinfo.bullet = ~bullet;
235 		v |= RichText::BULLET;
236 	}
237 	if(!IsNull(linespacing)) {
238 		formatinfo.linespacing = ~linespacing;
239 		v |= RichText::SPACING;
240 	}
241 	if(IsNumbering()) {
242 		(RichPara::NumberFormat&)formatinfo = GetNumbering();
243 		v |= RichText::NUMBERING;
244 	}
245 	if((RichText::TABS & formatinfo.paravalid) || tabs.GetCount()) {
246 		formatinfo.tab.Clear();
247 		for(int i = 0; i < tabs.GetCount(); i++) {
248 			RichPara::Tab tab;
249 			tab.pos = tabs.Get(i, 0);
250 			tab.align = (int)tabs.Get(i, 1);
251 			tab.fillchar = (int)tabs.Get(i, 2);
252 			formatinfo.tab.Add(tab);
253 		}
254 		v |= RichText::TABS;
255 	}
256 	if(!IsNull(tabsize)) {
257 		formatinfo.tabsize = ~tabsize;
258 		v |= RichText::TABSIZE;
259 	}
260 	if(!IsNull(ruler)) {
261 		formatinfo.ruler = ~ruler;
262 		v |= RichText::RULER;
263 	}
264 	if(!IsNull(rulerink)) {
265 		formatinfo.rulerink = ~rulerink;
266 		v |= RichText::RULERINK;
267 	}
268 	if(!IsNull(rulerstyle)) {
269 		formatinfo.rulerstyle = ~rulerstyle;
270 		v |= RichText::RULERSTYLE;
271 	}
272 	return v;
273 }
274 
275 struct RulerStyleDisplay : Display {
PaintUpp::RulerStyleDisplay276 	virtual void Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const
277 	{
278 		w.DrawRect(r, paper);
279 		if(!IsNull(q))
280 			RichPara::DrawRuler(w, r.left, (r.top + r.bottom) / 2 - 1, r.Width(), 2, ink, q);
281 	}
282 };
283 
ParaFormatting()284 ParaFormatting::ParaFormatting()
285 {
286 	CtrlLayout(*this);
287 	tabtype.Add(ALIGN_LEFT, t_("Left"));
288 	tabtype.Add(ALIGN_RIGHT, t_("Right"));
289 	tabtype.Add(ALIGN_CENTER, t_("Centered"));
290 	tabfill.Add(0, t_("None"));
291 	tabfill.Add(1, t_("...."));
292 	tabfill.Add(2, t_("----"));
293 	tabfill.Add(3, t_("__"));
294 	tabs.AddColumn(t_("Tab position"), 2).Edit(tabpos).SetConvert(tabpos);
295 	tabs.AddColumn(t_("Type"), 2).Edit(tabtype).SetConvert(tabtype).InsertValue(ALIGN_LEFT);
296 	tabs.AddColumn(t_("Fill"), 1).Edit(tabfill).SetConvert(tabfill).InsertValue(0);
297 	tabs.ColumnWidths("103 89 78");
298 	tabs.Appending().Removing().NoAskRemove();
299 	tabs.WhenAcceptEdit = tabs.WhenArrayAction = THISBACK(SetMod);
300 	linespacing.Add(0, "1.0");
301 	linespacing.Add(-1, "1.5");
302 	linespacing.Add(-2, "2.0");
303 	bullet.Add(RichPara::BULLET_NONE, RichEditImg::NoneBullet());
304 	bullet.Add(RichPara::BULLET_ROUND, RichEditImg::RoundBullet());
305 	bullet.Add(RichPara::BULLET_ROUNDWHITE, RichEditImg::RoundWhiteBullet());
306 	bullet.Add(RichPara::BULLET_BOX, RichEditImg::BoxBullet());
307 	bullet.Add(RichPara::BULLET_BOXWHITE, RichEditImg::BoxWhiteBullet());
308 	bullet.Add(RichPara::BULLET_TEXT, RichEditImg::TextBullet());
309 	bullet.SetDisplay(CenteredHighlightImageDisplay());
310 	bullet.SetLineCy(RichEditImg::RoundBullet().GetHeight() + Zy(2));
311 	for(int i = 0; i < 8; i++) {
312 		DropList& list = n[i];
313 		list.Add(Null);
314 		list.Add(RichPara::NUMBER_NONE, " - ");
315 		list.Add(RichPara::NUMBER_1, "1, 2, 3");
316 		list.Add(RichPara::NUMBER_0, "0, 1, 2");
317 		list.Add(RichPara::NUMBER_a, "a, b, c");
318 		list.Add(RichPara::NUMBER_A, "A, B, C");
319 		list.Add(RichPara::NUMBER_i, "i, ii, iii");
320 		list.Add(RichPara::NUMBER_I, "I, II, III");
321 		list <<= THISBACK(SetupIndent);
322 	}
323 	before_number <<=
324 	after_number <<=
325 	reset_number <<=
326 	bullet <<= THISBACK(SetupIndent);
327 
328 	newhdrftr <<= THISBACK(NewHdrFtr);
329 	hdrftr <<= THISBACK(EditHdrFtr);
330 	SyncHdrFtr();
331 
332 	EnableNumbering();
333 	rulerink.NullText("---");
334 	rulerstyle.SetDisplay(Single<RulerStyleDisplay>());
335 	rulerstyle.Add(Null);
336 	rulerstyle.Add(RichPara::RULER_SOLID);
337 	rulerstyle.Add(RichPara::RULER_DOT);
338 	rulerstyle.Add(RichPara::RULER_DASH);
339 }
340 
EnterStyle()341 void StyleManager::EnterStyle()
342 {
343 	RichText::FormatInfo f;
344 	const RichStyle& s = style.Get(list.GetKey());
345 	f.Set(s.format);
346 	para.Set(unit, f);
347 	height <<= RichEdit::DotToPt(s.format.GetHeight());
348 	face <<= s.format.GetFace();
349 	bold = s.format.IsBold();
350 	italic = s.format.IsItalic();
351 	underline = s.format.IsUnderline();
352 	strikeout = s.format.IsStrikeout();
353 	capitals = s.format.capitals;
354 	ink <<= s.format.ink;
355 	paper <<= s.format.paper;
356 	next <<= s.next;
357 	ClearModify();
358 	SetupFont0();
359 	para.EnableNumbering();
360 }
361 
GetFont(Font & font)362 void StyleManager::GetFont(Font& font)
363 {
364 	if(!IsNull(face))
365 		font.Face(~face);
366 	if(!IsNull(height))
367 		font.Height(RichEdit::PtToDot(~height));
368 	font.Bold(bold);
369 	font.Italic(italic);
370 	font.Underline(underline);
371 	font.Strikeout(strikeout);
372 }
373 
SetupFont0()374 void StyleManager::SetupFont0()
375 {
376 	Font font = Arial(120);
377 	GetFont(font);
378 	para.SetFont(font);
379 }
380 
SetupFont()381 void StyleManager::SetupFont()
382 {
383 	SetupFont0();
384 	para.SetupIndent();
385 }
386 
SaveStyle()387 void StyleManager::SaveStyle()
388 {
389 	if(list.IsCursor()) {
390 		Uuid id = list.GetKey();
391 		RichStyle& s = style.Get(list.GetKey());
392 		if(Ctrl::IsModifiedDeep() || para.IsChanged()) {
393 			dirty.FindAdd(id);
394 			RichText::FormatInfo f;
395 			para.Get(f);
396 			s.format = f;
397 			GetFont(s.format);
398 			s.format.capitals = capitals;
399 			s.format.ink = ~ink;
400 			s.format.paper = ~paper;
401 		}
402 		if(String(list.Get(1)) != s.name) {
403 			dirty.FindAdd(id);
404 			s.name = list.Get(1);
405 		}
406 		if((Uuid)~next != s.next) {
407 			dirty.FindAdd(id);
408 			s.next = ~next;
409 		}
410 	}
411 }
412 
Create()413 void StyleManager::Create()
414 {
415 	Uuid id = Uuid::Create();
416 	style.Add(id, style.Get(list.GetKey()));
417 	style.Top().next = id;
418 	dirty.FindAdd(id);
419 	list.Add(id);
420 	list.GoEnd();
421 	list.StartEdit();
422 }
423 
Remove()424 void StyleManager::Remove()
425 {
426 	if(list.GetCount() > 1 && (Uuid)list.GetKey() != RichStyle::GetDefaultId()) {
427 		dirty.FindAdd(list.GetKey());
428 		style.Remove(list.GetCursor());
429 		list.Remove(list.GetCursor());
430 	}
431 }
432 
Menu(Bar & bar)433 void StyleManager::Menu(Bar& bar)
434 {
435 	bar.Add(t_("Create new style.."), THISBACK(Create))
436 	   .Key(K_INSERT);
437 	bar.Add(t_("Remove style"), THISBACK(Remove))
438 	   .Key(K_DELETE);
439 	bar.Add(t_("Rename.."), callback(&list, &ArrayCtrl::DoEdit))
440 	   .Key(K_CTRL_ENTER);
441 }
442 
ReloadNextStyles()443 void StyleManager::ReloadNextStyles()
444 {
445 	next.ClearList();
446 	for(int i = 0; i < list.GetCount(); i++)
447 		next.Add(list.Get(i, 0), list.Get(i, 1));
448 }
449 
Paint(Draw & w,const Rect & r,const Value & q,Color ink,Color paper,dword style) const450 void RichEdit::DisplayDefault::Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const
451 {
452 	String text = q;
453 	w.DrawRect(r, paper);
454 	DrawSmartText(w, r.left, r.top, r.Width(), text, StdFont().Bold(), ink);
455 }
456 
Set(const RichText & text,const Uuid & current)457 void StyleManager::Set(const RichText& text, const Uuid& current)
458 {
459 	list.Clear();
460 	int i;
461 	for(i = 0; i < text.GetStyleCount(); i++)
462 		list.Add(text.GetStyleId(i), text.GetStyle(i).name);
463 	list.Sort(1, RichEdit::CompareStyle);
464 	for(i = 0; i < text.GetStyleCount(); i++) {
465 		Uuid id = list.Get(i, 0);
466 		style.Add(id, text.GetStyle(id));
467 	}
468 	int q = list.Find(RichStyle::GetDefaultId());
469 	if(q >= 0)
470 		list.SetDisplay(q, 0, Single<RichEdit::DisplayDefault>());
471 	ReloadNextStyles();
472 	list.FindSetCursor(current);
473 }
474 
Set(const char * qtf)475 void StyleManager::Set(const char *qtf)
476 {
477 	RichText txt = ParseQTF(qtf);
478 	Set(txt);
479 }
480 
IsChanged() const481 bool StyleManager::IsChanged() const
482 {
483 	return dirty.GetCount() || IsModifiedDeep();
484 }
485 
Get(RichText & text)486 void StyleManager::Get(RichText& text)
487 {
488 	SaveStyle();
489 	for(int i = 0; i < dirty.GetCount(); i++) {
490 		Uuid id = dirty[i];
491 		int q = style.Find(id);
492 		if(q >= 0)
493 			text.SetStyle(id, style.Get(id));
494 		else
495 			text.RemoveStyle(id);
496 	}
497 }
498 
Get()499 RichText StyleManager::Get()
500 {
501 	RichText output;
502 	output.SetStyles(style);
503 	return output;
504 }
505 
GetQTF()506 String StyleManager::GetQTF()
507 {
508 	return AsQTF(Get());
509 }
510 
Setup(const Vector<int> & faces,int aunit)511 void StyleManager::Setup(const Vector<int>& faces, int aunit)
512 {
513 	unit = aunit;
514 	height.Clear();
515 	for(int i = 0; RichEdit::fh[i]; i++)
516 		height.AddList(RichEdit::fh[i]);
517 	face.ClearList();
518 	SetupFaceList(face);
519 	for(int i = 0; i < faces.GetCount(); i++)
520 		face.Add(faces[i]);
521 }
522 
StyleManager()523 StyleManager::StyleManager()
524 {
525 	CtrlLayoutOKCancel(*this, t_("Styles"));
526 	list.NoHeader().NoGrid();
527 	list.AddKey();
528 	list.AddColumn().Edit(name);
529 	list.WhenEnterRow = THISBACK(EnterStyle);
530 	list.WhenKillCursor = THISBACK(SaveStyle);
531 	list.WhenBar = THISBACK(Menu);
532 	list.WhenAcceptEdit = THISBACK(ReloadNextStyles);
533 	ink.NotNull();
534 	face <<= height <<= italic <<= bold <<= underline <<= strikeout <<= THISBACK(SetupFont);
535 	Vector<int> ffs;
536 	Vector<int> ff;
537 	ff.Add(Font::ARIAL);
538 	ff.Add(Font::ROMAN);
539 	ff.Add(Font::COURIER);
540 	Setup(ff, UNIT_DOT);
541 }
542 
543 }
544