#include "RichEdit.h" namespace Upp { void RichEdit::ApplyFormat(dword charvalid, dword paravalid) { if(IsReadOnly()) return; RichText::FormatInfo f = formatinfo; f.charvalid = charvalid; f.paravalid = paravalid; if(objectpos >= 0) { ModifyFormat(objectpos, f, 1); Finish(); } if(IsSelection()) { if(tablesel) { NextUndo(); SaveTable(tablesel); text.ApplyTableFormatInfo(tablesel, cells, f); } else { int l = min(cursor, anchor); int h = max(cursor, anchor); RichPos rp = text.GetRichPos(h); if(rp.posinpara == 0 && h > l) { RichPos rp1 = text.GetRichPos(h - 1); if(InSameTxt(rp, rp1)) h--; } ModifyFormat(l, f, h - l); } Finish(); } else if(cursorp.paralen == 0) { ModifyFormat(cursor, f, 0); Finish(); } else if(f.paravalid) { ModifyFormat(cursor, f, 0); Finish(); } else RefreshBar(); } void RichEdit::ApplyFormatInfo(const RichText::FormatInfo& fi) { fi.ApplyTo(formatinfo); formatinfo.charvalid |= fi.charvalid; formatinfo.paravalid |= fi.paravalid; ApplyFormat(fi.charvalid, fi.paravalid); } void RichEdit::Bold() { NextUndo(); formatinfo.Bold(!(formatinfo.IsBold() && (formatinfo.charvalid & RichText::BOLD))); ApplyFormat(RichText::BOLD); } void RichEdit::Italic() { NextUndo(); formatinfo.Italic(!(formatinfo.IsItalic() && (formatinfo.charvalid & RichText::ITALIC))); ApplyFormat(RichText::ITALIC); } void RichEdit::Underline() { NextUndo(); formatinfo.Underline(!(formatinfo.IsUnderline() && (formatinfo.charvalid & RichText::UNDERLINE))); ApplyFormat(RichText::UNDERLINE); } void RichEdit::Strikeout() { NextUndo(); formatinfo.Strikeout(!(formatinfo.IsStrikeout() && (formatinfo.charvalid & RichText::STRIKEOUT))); ApplyFormat(RichText::STRIKEOUT); } void RichEdit::Capitals() { NextUndo(); formatinfo.capitals = !formatinfo.capitals && (formatinfo.charvalid & RichText::CAPITALS); ApplyFormat(RichText::CAPITALS); } void RichEdit::SetScript(int i) { NextUndo(); formatinfo.sscript = i; ApplyFormat(RichText::SSCRIPT); } void RichEdit::SetFace() { NextUndo(); formatinfo.Face(~face); ApplyFormat(RichText::FACE); SetFocus(); } void RichEdit::SetHeight() { NextUndo(); formatinfo.Height(PtToDot(~height)); ApplyFormat(RichText::HEIGHT); SetFocus(); } void RichEdit::SetInk() { NextUndo(); formatinfo.ink = ~ink; ApplyFormat(RichText::INK); SetFocus(); } void RichEdit::SetPaper() { NextUndo(); formatinfo.paper = ~paper; ApplyFormat(RichText::PAPER); SetFocus(); } void RichEdit::SetLanguage() { NextUndo(); formatinfo.language = (int)~language; ApplyFormat(RichText::LANGUAGE); SetFocus(); } void RichEdit::Language() { WithRichLanguageLayout d; CtrlLayoutOKCancel(d, t_("Language")); d.lang <<= ~language; if(d.Run() != IDOK) return; formatinfo.language = (int)~d.lang; ApplyFormat(RichText::LANGUAGE); SetFocus(); if(!language.HasKey((int)~d.lang)) { Vector h; for(int i = 0; i < language.GetCount(); i++) h.Add(language.GetKey(i)); h.Add(~d.lang); SetupLanguage(pick(h)); } } void RichEdit::IndentMark() { RichRuler::Marker m; int l = formatinfo.lm; int r = cursorc.textpage.Width() - formatinfo.rm; m.pos = l + formatinfo.indent; m.minpos = max(l, 0); m.maxpos = max(r - 120, 0); m.top = true; m.image = formatinfo.paravalid & RichText::INDENT ? RichEditImg::Indent() : RichEditImg::IndentMixed(); ruler.Set(2, m); } void RichEdit::ReadFormat() { if(objectpos >= 0) formatinfo = text.GetFormatInfo(objectpos, 1); else if(IsSelection()) if(tablesel) formatinfo = text.GetTableFormatInfo(tablesel, cells); else formatinfo = text.GetFormatInfo(min(cursor, anchor), abs(cursor - anchor)); else { RichPos p = cursorp; if(cursor && p.posinpara) p = text.GetRichPos(cursor - 1); formatinfo.Set(p.format); } ShowFormat(); } void RichEdit::ShowFormat() { RefreshBar(); if(formatinfo.charvalid & RichText::FACE) face <<= formatinfo.GetFace(); else face <<= Null; if(formatinfo.charvalid & RichText::HEIGHT) height <<= DotToPt(formatinfo.GetHeight()); else height <<= Null; if(formatinfo.charvalid & RichText::LINK) hyperlink <<= formatinfo.link; else hyperlink <<= Null; if(formatinfo.charvalid & RichText::INDEXENTRY) indexentry <<= formatinfo.indexentry; else indexentry <<= Null; if(formatinfo.charvalid & RichText::INK) ink <<= formatinfo.ink; else ink <<= Null; if(formatinfo.charvalid & RichText::PAPER) paper <<= formatinfo.paper; else paper <<= Null; if(formatinfo.charvalid & RichText::LANG) language <<= (int)formatinfo.language; else language <<= Null; if(IsSelection()) label <<= Null; else label <<= formatinfo.label; int l = formatinfo.lm; int r = cursorc.textpage.Width() - formatinfo.rm; RichRuler::Marker m; m.pos = l; m.minpos = 0; m.maxpos = max(r - formatinfo.indent - 120, 0); m.image = formatinfo.paravalid & RichText::LM ? RichEditImg::Margin() : RichEditImg::MarginMixed(); ruler.Set(0, m); m.pos = r; m.minpos = max(l + formatinfo.indent + 120, 0); m.maxpos = cursorc.textpage.Width(); m.image = formatinfo.paravalid & RichText::RM ? RichEditImg::Margin() : RichEditImg::MarginMixed(); ruler.Set(1, m); IndentMark(); int maxpos = 0; m.minpos = 0; m.deletable = true; if(formatinfo.paravalid & RichText::TABS) { for(int i = 0; i < formatinfo.tab.GetCount(); i++) { RichPara::Tab tab = formatinfo.tab[i]; m.pos = tab.pos; if(tab.pos > maxpos) maxpos = tab.pos; switch(tab.align) { case ALIGN_LEFT: m.image = RichEditImg::LeftTab(); break; case ALIGN_RIGHT: m.image = RichEditImg::RightTab(); break; case ALIGN_CENTER: m.image = RichEditImg::CenterTab(); break; } ruler.Set(i + 3, m); } ruler.SetTabs(maxpos, formatinfo.tabsize); ruler.SetCount(formatinfo.tab.GetCount() + 3); } else { ruler.SetTabs(INT_MAX / 2, 1); ruler.SetCount(3); } if(formatinfo.paravalid & RichText::STYLE) style <<= formatinfo.styleid; else style <<= Null; setstyle->Enable(!IsSelection()); } void RichEdit::HighLightTab(int r) { RichRuler::Marker m = ruler[r + 3]; RichPara::Tab tab = formatinfo.tab[r]; m.image = tab.align == ALIGN_RIGHT ? RichEditImg::RightTabTrack() : tab.align == ALIGN_CENTER ? RichEditImg::CenterTabTrack() : RichEditImg::LeftTabTrack(); ruler.Set(r + 3, m); } void RichEdit::Hyperlink() { String s = formatinfo.link; if(!IsSelection() && !IsNull(s) && cursorp.format.link == s && text[cursor] != '\n') { int l = cursor - 1; while(l >= 0 && text[l] != '\n' && text.GetRichPos(l).format.link == s) l--; l++; int h = cursor; while(h < text.GetLength() && text[h] != '\n' && text.GetRichPos(h).format.link == s) h++; if(l < h) Select(l, h - l); } WString linktext; WhenHyperlink(s, linktext); if(s != formatinfo.link || linktext.GetLength()) { formatinfo.link = s; hyperlink <<= s; NextUndo(); ApplyFormat(RichText::LINK); if(linktext.GetLength()) { RemoveSelection(); RichPara p; p.format = formatinfo; p.Cat(linktext, formatinfo); RichText txt; txt.SetStyles(text.GetStyles()); txt.Cat(p); Insert(cursor, txt, true); Move(cursor + linktext.GetCount(), false); } } SetFocus(); } void RichEdit::Label() { if(IsSelection()) return; String s = formatinfo.label; WhenLabel(s); if(s != formatinfo.label) { formatinfo.label = s; NextUndo(); ApplyFormat(0, RichText::LABEL); SetFocus(); } } void RichEdit::IndexEntry() { String s = formatinfo.indexentry.ToString(); String s0 = s; WhenIndexEntry(s); if(s != s0) { formatinfo.indexentry = s.ToWString(); ApplyFormat(RichText::INDEXENTRY); NextUndo(); SetFocus(); } } void RichEdit::BeginRulerTrack() { NextUndo(); SaveFormat(); int r = ruler.GetTrack(); if(r < 0) return; RichRuler::Marker m = ruler[r]; switch(r) { case 0: case 1: m.image = RichEditImg::MarginTrack(); break; case 2: m.image = RichEditImg::IndentTrack(); break; default: HighLightTab(r - 3); return; } ruler.Set(r, m); } void RichEdit::SetParaFormat(dword paravalid) { RichText::FormatInfo f = formatinfo; f.charvalid = 0; f.paravalid = paravalid; if(IsSelection()) if(tablesel) text.ApplyTableFormatInfo(tablesel, cells, f); else text.ApplyFormatInfo(min(cursor, anchor), f, abs(cursor - anchor)); else text.ApplyFormatInfo(cursor, f, 0); } void RichEdit::RulerTrack() { int r = ruler.GetTrack(); if(r < 0) return; RichRuler::Marker m = ruler[r]; switch(r) { case 0: formatinfo.lm = m.pos; SetParaFormat(RichText::LM); IndentMark(); break; case 1: formatinfo.rm = cursorc.textpage.Width() - m.pos; SetParaFormat(RichText::RM); break; case 2: formatinfo.indent = m.pos - formatinfo.lm; SetParaFormat(RichText::INDENT); break; default: formatinfo.tab[r - 3].pos = m.pos; SetParaFormat(RichText::TABS); int maxpos = 0; for(int i = 0; i < formatinfo.tab.GetCount(); i++) { RichPara::Tab tab = formatinfo.tab[i]; if(tab.pos > maxpos) maxpos = tab.pos; } ruler.SetTabs(maxpos, formatinfo.tabsize); break; } FinishNF(); } void RichEdit::TabAdd(int align) { RichPara::Tab tab; tab.pos = ruler.GetPos(); tab.align = align; if(formatinfo.tab.GetCount() > 30000 || tab.pos < 0 || tab.pos >= cursorc.textpage.Width()) return; formatinfo.tab.Add(tab); SetParaFormat(RichText::TABS); Finish(); } void RichEdit::AddTab() { NextUndo(); SaveFormat(); TabAdd(ruler.GetNewTabAlign()); } void RichEdit::TabMenu() { NextUndo(); int r = ruler.GetTrack() - 3; if(r >= 0) HighLightTab(r); CallbackArgTarget align; CallbackArgTarget fill; MenuBar menu; menu.Add(t_("Left"), RichEditImg::LeftTab(), align[ALIGN_LEFT]); menu.Add(t_("Right"), RichEditImg::RightTab(), align[ALIGN_RIGHT]); menu.Add(t_("Center"), RichEditImg::CenterTab(), align[ALIGN_CENTER]); if(r >= 0) { int f = formatinfo.tab[r].fillchar; menu.Separator(); menu.Add(t_("No fill"), fill[0]) .Radio(f == 0); menu.Add(t_("Fill with ...."), fill[1]) .Radio(f == 1); menu.Add(t_("Fill with ----"), fill[2]) .Radio(f == 2); menu.Add(t_("Fill with __"), fill[3]) .Radio(f == 3); menu.Separator(); menu.Add(t_("Remove"), fill[-1]); } menu.Execute(); if(!IsNull(align)) { SaveFormat(); if(r >= 0) { formatinfo.tab[r].align = (int)align; SetParaFormat(RichText::TABS); } else TabAdd(align); } if(!IsNull(fill) && r >= 0) { SaveFormat(); if(r >= 0) { if(fill == -1) formatinfo.tab[r].pos = Null; else formatinfo.tab[r].fillchar = (int)fill; SetParaFormat(RichText::TABS); } } Finish(); } void RichEdit::AlignLeft() { NextUndo(); formatinfo.align = ALIGN_LEFT; ApplyFormat(0, RichText::ALIGN); } void RichEdit::AlignRight() { NextUndo(); formatinfo.align = ALIGN_RIGHT; ApplyFormat(0, RichText::ALIGN); } void RichEdit::AlignCenter() { NextUndo(); formatinfo.align = ALIGN_CENTER; ApplyFormat(0, RichText::ALIGN); } void RichEdit::AlignJustify() { NextUndo(); formatinfo.align = ALIGN_JUSTIFY; ApplyFormat(0, RichText::ALIGN); } void RichEdit::SetBullet(int bullet) { NextUndo(); if((formatinfo.paravalid & RichText::BULLET) && formatinfo.bullet == bullet) { formatinfo.bullet = RichPara::BULLET_NONE; formatinfo.indent = formatinfo.paravalid & RichText::STYLE ? text.GetStyle(formatinfo.styleid).format.indent : 0; } else { formatinfo.bullet = bullet; formatinfo.indent = bullet_indent; } ApplyFormat(0, RichText::INDENT|RichText::BULLET); } void RichEdit::Style() { NextUndo(); SaveFormat(cursor, 0); formatinfo.Set(text.GetStyle((Uuid)~style).format); ApplyFormat(0, RichText::STYLE); SetFocus(); Finish(); } void RichEdit::AdjustObjectSize() { NextUndo(); RichObject obj = cursorp.object; if(!obj) return; WithObjectSizeLayout d; CtrlLayoutOKCancel(d, t_("Object position")); Size sz = obj.GetSize(); Size psz = GetPhysicalSize(obj); if(psz.cx == 0) psz.cx = 2000; if(psz.cy == 0) psz.cy = 2000; d.width.Set(unit, sz.cx); d.height.Set(unit, sz.cy); d.widthp.SetInc(5).Pattern("%.1f"); d.widthp <<= 100.0 * sz.cx / psz.cx; d.heightp.SetInc(5).Pattern("%.1f"); d.heightp <<= 100.0 * sz.cy / psz.cy; d.keepratio = obj.IsKeepRatio(); d.width <<= d.height <<= d.widthp <<= d.heightp <<= d.Breaker(IDYES); d.ydelta.WithSgn().Set(unit, obj.GetYDelta()); d.keepratio <<= d.Breaker(IDNO); for(;;) { switch(d.Run()) { case IDCANCEL: return; case IDYES: if(d.width.HasFocus() && !IsNull(d.width)) { d.widthp <<= 100 * (double)~d.width / psz.cx; if(d.keepratio) { d.height <<= psz.cy * (double)~d.width / psz.cx; d.heightp <<= ~d.widthp; } } if(d.height.HasFocus() && !IsNull(d.height)) { d.heightp <<= 100 * (double)~d.height / psz.cy; if(d.keepratio) { d.width <<= psz.cx * (double)~d.height / psz.cy; d.widthp <<= ~d.heightp; } } if(d.widthp.HasFocus() && !IsNull(d.widthp)) { d.width <<= psz.cx * (double)~d.widthp / 100; if(d.keepratio) { d.height <<= psz.cy * (double)~d.width / psz.cx; d.heightp <<= ~d.widthp; } } if(d.heightp.HasFocus() && !IsNull(d.heightp)) { d.height <<= psz.cy * (double)~d.heightp / 100; if(d.keepratio) { d.width <<= psz.cx * (double)~d.height / psz.cy; d.widthp <<= ~d.heightp; } } break; case IDNO: if(d.keepratio && !IsNull(d.width)) { d.widthp <<= 100 * (double)~d.width / psz.cx; if(d.keepratio) { d.height <<= psz.cy * (double)~d.width / psz.cx; d.heightp <<= ~d.widthp; } } break; case IDOK: if(!IsNull(d.width) && (int)~d.width > 0) sz.cx = ~d.width; if(!IsNull(d.height) && (int)~d.height > 0) sz.cy = ~d.height; obj.SetSize(sz); if(!IsNull(d.ydelta)) obj.SetYDelta(~d.ydelta); obj.KeepRatio(d.keepratio); ReplaceObject(obj); return; } } } }