ultimatepp/uppsrc/RichEdit/Formating.cpp
Mirek Fidler c119e90c6c PixelMode
2024-12-17 15:37:55 +01:00

650 lines
14 KiB
C++

#include "RichEdit.h"
namespace Upp {
Point RichEdit::GetPreedit()
{
Rect r = GetCaretRect();
if(formatinfo.sscript == 2) {
Point p = r.BottomRight();
p.y -= 3 * r.GetHeight() / 5;
return p;
}
return r.TopRight();
}
Font RichEdit::GetPreeditFont()
{
Font fnt = formatinfo;
int h = abs(fnt.GetHeight());
if(formatinfo.sscript)
h = 3 * h / 5;
return fnt(max(GetZoom() * abs(h), 1));
}
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, unit));
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<TopWindow> 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<int> 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(), unit);
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<int> align;
CallbackArgTarget<int> 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<TopWindow> 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;
}
}
}
}