From: Juergen Spitzmueller Date: Sat, 28 Dec 2019 12:43:17 +0000 (+0100) Subject: Centralize code to markup deleted complex objects (with tikz) in output X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=ab38872003a5dce3268e530bd46cdf3c668ce224;p=features.git Centralize code to markup deleted complex objects (with tikz) in output This fixes #9293 --- diff --git a/lib/chkconfig.ltx b/lib/chkconfig.ltx index 14230d4674..b8f90f920f 100644 --- a/lib/chkconfig.ltx +++ b/lib/chkconfig.ltx @@ -435,6 +435,7 @@ \TestPackage{tcolorbox} \TestPackage{textcomp} \TestPackage{thswitch} +\TestPackage{tikz} \TestPackage[turkmen.ldf]{turkmen} \TestPackage{ulem} \TestPackage{undertilde} diff --git a/src/Changes.cpp b/src/Changes.cpp index f7167a2ba9..ed9205d530 100644 --- a/src/Changes.cpp +++ b/src/Changes.cpp @@ -434,9 +434,11 @@ int Changes::latexMarkChange(otexstream & os, BufferParams const & bparams, || runparams.flavor == OutputParams::DVILUATEX); if (oldChange.type != Change::UNCHANGED) { - // close \lyxadded or \lyxdeleted - os << '}'; - column++; + if (oldChange.type != Change::DELETED || runparams.ctObject != OutputParams::CT_OMITOBJECT) { + // close \lyxadded or \lyxdeleted + os << '}'; + column++; + } if (oldChange.type == Change::DELETED && !runparams.wasDisplayMath && !dvipost) --runparams.inulemcmd; @@ -449,9 +451,19 @@ int Changes::latexMarkChange(otexstream & os, BufferParams const & bparams, docstring macro_beg; if (change.type == Change::DELETED) { - macro_beg = from_ascii("\\lyxdeleted"); - if (!runparams.inDisplayMath && !dvipost) - ++runparams.inulemcmd; + if (runparams.ctObject == OutputParams::CT_OMITOBJECT) + return 0; + else if (runparams.ctObject == OutputParams::CT_OBJECT) + macro_beg = from_ascii("\\lyxobjdeleted"); + else if (runparams.ctObject == OutputParams::CT_DISPLAYOBJECT) + macro_beg = from_ascii("\\lyxdisplayobjdeleted"); + else if (runparams.ctObject == OutputParams::CT_UDISPLAYOBJECT) + macro_beg = from_ascii("\\lyxudisplayobjdeleted"); + else { + macro_beg = from_ascii("\\lyxdeleted"); + if (!runparams.inDisplayMath && !dvipost) + ++runparams.inulemcmd; + } } else if (change.type == Change::INSERTED) macro_beg = from_ascii("\\lyxadded"); @@ -460,15 +472,6 @@ int Changes::latexMarkChange(otexstream & os, BufferParams const & bparams, bparams.authors().get(change.author), chgTime, runparams); - // signature needed by \lyxsout to correctly strike out display math - if (change.type == Change::DELETED && runparams.inDisplayMath - && !dvipost) { - if (os.blankLine()) - str += from_ascii("\\\\\\noindent\n"); - else - str += from_ascii("\\\\\\\\\n"); - } - os << str; column += str.size(); diff --git a/src/LaTeXFeatures.cpp b/src/LaTeXFeatures.cpp index d13c35d891..e80fcbf333 100644 --- a/src/LaTeXFeatures.cpp +++ b/src/LaTeXFeatures.cpp @@ -298,21 +298,83 @@ static docstring const changetracking_xcolor_ulem_hyperref_cb_def = from_ascii( static docstring const changetracking_tikz_object_sout_def = from_ascii( "%% Strike out display math and text objects with tikz\n" - "\\usepackage{tikz}\n" "\\usetikzlibrary{calc}\n" "\\newcommand{\\lyxobjectsout}[1]{%\n" " \\bgroup%\n" " \\color{lyxdeleted}%\n" - " \\tikz[baseline=(obj.base)]{\n" - " \\node[inner sep=0pt,outer sep=0pt](obj){#1};\n" - " \\draw($(obj.south west)+(2em,.5em)$)--($(obj.north east)-(2em,.5em)$);\n" + " \\tikz{\n" + " \\node[inner sep=0pt,outer sep=0pt](lyxdelobj){#1};\n" + " \\draw($(lyxdelobj.south west)+(2em,.5em)$)--($(lyxdelobj.north east)-(2em,.5em)$);\n" " }\n" " \\egroup%\n" "}\n"); +static docstring const changetracking_xcolor_ulem_object_def = from_ascii( + "%% Change tracking with ulem and xcolor: ct markup for complex objects\n" + "\\DeclareRobustCommand{\\lyxobjdeleted}[4][]{\\lyxobjectsout{#4}}\n" + "\\DeclareRobustCommand{\\lyxdisplayobjdeleted}[4][]{\\lyxobjectsout{\\parbox{\\linewidth}{#4}}}\n" + "\\DeclareRobustCommand{\\lyxudisplayobjdeleted}[4][]{%\n" + " \\raisebox{-\\belowdisplayshortskip}{%\n" + " \\lyxobjectsout{\\parbox[b]{\\linewidth}{#4}}}%\n" + "}\n"); + +static docstring const changetracking_xcolor_ulem_cb_object_def = from_ascii( + "%% Change tracking with ulem, xcolor and changebars:ct markup for complex objects\n" + "\\DeclareRobustCommand{\\lyxobjdeleted}[4][]{%\n" + " \\protect\\cbstart\\lyxobjectsout{#4}%\n" + " \\protect\\cbend%\n" + "}\n" + "\\DeclareRobustCommand{\\lyxdisplayobjdeleted}[4][]{%\n" + " \\protect\\cbstart%\n" + " \\lyxobjectsout{\\parbox{\\linewidth}{#4}}%\n" + " \\protect\\cbend%\n" + "}\n" + "\\DeclareRobustCommand{\\lyxudisplayobjdeleted}[4][]{%\n" + " \\raisebox{-\\belowdisplayshortskip}{%\n" + " \\protect\\cbstart%\n" + " \\lyxobjectsout{\\parbox[b]{\\linewidth}{#4}}}%\n" + " \\protect\\cbend%\n" + "}\n"); + +static docstring const changetracking_xcolor_ulem_hyperref_object_def = from_ascii( + "%% Change tracking with ulem, xcolor, and hyperref: ct markup for complex objects\n" + "\\DeclareRobustCommand{\\lyxobjdeleted}[4][]{\\texorpdfstring{\\lyxobjectsout{#4}}{}}\n" + "\\DeclareRobustCommand{\\lyxdisplayobjdeleted}[4][]{%\n" + " \\texorpdfstring{\\lyxobjectsout{\\parbox{\\linewidth}{#4}}}{}%\n" + "}\n" + "\\DeclareRobustCommand{\\lyxudisplayobjdeleted}[4][]{%\n" + " \\texorpdfstring{\\raisebox{-\\belowdisplayshortskip}{%\n" + " \\lyxobjectsout{\\parbox[b]{\\linewidth}{#4}}}}{}%\n" + "}\n"); + +static docstring const changetracking_xcolor_ulem_hyperref_cb_object_def = from_ascii( + "%% Change tracking with ulem, xcolor, hyperref and changebars:\n" + "%% ct markup for complex objects\n" + "\\DeclareRobustCommand{\\lyxobjdeleted}[4][]{%\n" + " \\texorpdfstring{\\protect\\cbstart\\lyxobjectsout{#4}%\n" + " \\protect\\cbend}{}%\n" + "}\n" + "\\DeclareRobustCommand{\\lyxdisplayobjdeleted}[4][]{%\n" + " \\texorpdfstring{\\protect\\cbstart%\n" + " \\lyxobjectsout{\\parbox{\\linewidth}{#4}}%\n" + " \\protect\\cbend%\n" + " }{}%\n" + "}\n" + "\\DeclareRobustCommand{\\lyxudisplayobjdeleted}[4][]{%\n" + " \\texorpdfstring{\\protect\\cbstart%\n" + " \\raisebox{-\\belowdisplayshortskip}{%\n" + " \\lyxobjectsout{\\parbox[b]{\\linewidth}{#4}}%\n" + " }%\n" + " }{}%\n" + "}\n"); + static docstring const changetracking_none_def = from_ascii( + "%% Change tracking: Disable markup in output\n" "\\newcommand{\\lyxadded}[3]{#3}\n" - "\\newcommand{\\lyxdeleted}[3]{}\n"); + "\\newcommand{\\lyxdeleted}[3]{}\n" + "\\newcommand{\\lyxobjdeleted}[3]{}\n" + "\\newcommand{\\lyxdisplayobjdeleted}[3]{}\n" + "\\newcommand{\\lyxudisplayobjdeleted}[3]{}\n"); static docstring const textgreek_LGR_def = from_ascii( "\\DeclareFontEncoding{LGR}{}{}\n"); @@ -1089,6 +1151,7 @@ char const * simplefeatures[] = { "tablefootnote", "afterpage", "tabularx", + "tikz", "xltabular", "chessboard", "xskak", @@ -1695,8 +1758,35 @@ TexString LaTeXFeatures::getMacros() const } } - if (mustProvide("ct-tikz-object-sout")) + if (mustProvide("ct-tikz-object-sout")) { + if (!mustProvide("ct-xcolor-ulem")) { + streamsize const prec = macros.os().precision(2); + + RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext)); + macros << "\\providecolor{lyxadded}{rgb}{" + << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n"; + + RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext)); + macros << "\\providecolor{lyxdeleted}{rgb}{" + << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n"; + + macros.os().precision(prec); + } + macros << changetracking_tikz_object_sout_def; + + if (isRequired("changebar")) { + if (isRequired("hyperref")) + macros << changetracking_xcolor_ulem_hyperref_cb_object_def; + else + macros << changetracking_xcolor_ulem_cb_object_def; + } else { + if (isRequired("hyperref")) + macros << changetracking_xcolor_ulem_hyperref_object_def; + else + macros << changetracking_xcolor_ulem_object_def; + } + } if (mustProvide("ct-none")) macros << changetracking_none_def; diff --git a/src/OutputParams.cpp b/src/OutputParams.cpp index de4b893728..d26955e69a 100644 --- a/src/OutputParams.cpp +++ b/src/OutputParams.cpp @@ -28,7 +28,7 @@ OutputParams::OutputParams(Encoding const * enc) wasDisplayMath(false), inComment(false), openbtUnit(false), only_childbibs(false), inTableCell(NO), inFloat(NONFLOAT), inIndexEntry(false), inIPA(false), inDeletedInset(0), - changeOfDeletedInset(Change::UNCHANGED), + changeOfDeletedInset(Change::UNCHANGED), ctObject(CT_NORMAL), par_begin(0), par_end(0), lastid(-1), lastpos(0), isLastPar(false), dryrun(false), silent(false), pass_thru(false), html_disable_captions(false), html_in_par(false), diff --git a/src/OutputParams.h b/src/OutputParams.h index a2eb397777..5503d8b7cd 100644 --- a/src/OutputParams.h +++ b/src/OutputParams.h @@ -60,6 +60,14 @@ public: SUBFLOAT }; + enum CtObject { + CT_NORMAL, + CT_OBJECT, + CT_DISPLAYOBJECT, + CT_UDISPLAYOBJECT, + CT_OMITOBJECT + }; + OutputParams(Encoding const *); ~OutputParams(); @@ -272,14 +280,19 @@ public: /** Whether we are inside an inset that is logically deleted. * A value > 0 indicates a deleted inset. - */ + */ int inDeletedInset; /** The change information of the outermost logically deleted inset. * changeOfDeletedInset shall only be evaluated if inDeletedInset > 0. - */ + */ Change changeOfDeletedInset; + /** What kind of change tracking object is this? + * Relevant for strikeout method in output + */ + mutable CtObject ctObject; + /** allow output of only part of the top-level paragraphs * par_begin: beginning paragraph */ diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index 198705c3b8..389b43699e 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -2477,9 +2477,14 @@ void Paragraph::latex(BufferParams const & bparams, Change const & change = runparams.inDeletedInset ? runparams.changeOfDeletedInset : lookupChange(i); + char_type const c = d->text_[i]; + // Check whether a display math inset follows - if (d->text_[i] == META_INSET + if (c == META_INSET && i >= start_pos && (end_pos == -1 || i < end_pos)) { + if (isDeleted(i)) + runparams.ctObject = getInset(i)->CtObject(runparams); + InsetMath const * im = getInset(i)->asInsetMath(); if (im && im->asHullInset() && im->asHullInset()->outerDisplay()) { @@ -2593,8 +2598,6 @@ void Paragraph::latex(BufferParams const & bparams, } } - char_type const c = d->text_[i]; - // A display math inset inside an ulem command will be output // as a box of width \linewidth, so we have to either disable // indentation if the inset starts a paragraph, or start a new diff --git a/src/insets/Inset.h b/src/insets/Inset.h index 3f7178f6cf..ae5af7cc78 100644 --- a/src/insets/Inset.h +++ b/src/insets/Inset.h @@ -20,6 +20,7 @@ #include "InsetLayout.h" #include "LayoutEnums.h" #include "OutputEnums.h" +#include "OutputParams.h" #include "support/strfwd.h" #include "support/types.h" @@ -471,6 +472,8 @@ public: /// does this inset try to use all available space (like \\hfill does)? virtual bool isHfill() const { return false; } + virtual OutputParams::CtObject CtObject(OutputParams const &) const { return OutputParams::CT_NORMAL; } + enum DisplayType { Inline = 0, AlignLeft, diff --git a/src/insets/InsetFloat.cpp b/src/insets/InsetFloat.cpp index 7093541c93..5e1dd3d7fc 100644 --- a/src/insets/InsetFloat.cpp +++ b/src/insets/InsetFloat.cpp @@ -322,8 +322,10 @@ void InsetFloat::validate(LaTeXFeatures & features) const if (features.inFloat()) features.require("subfig"); - if (features.inDeletedInset()) + if (features.inDeletedInset()) { + features.require("tikz"); features.require("ct-tikz-object-sout"); + } features.useFloat(params_.type, features.inFloat()); features.inFloat(true); @@ -439,8 +441,12 @@ void InsetFloat::latex(otexstream & os, OutputParams const & runparams_in) const os << '\n'; if (runparams.inDeletedInset) { - os << "\\lyxobjectsout{%" << breakln; - os << "\\parbox{\\linewidth}{%" << breakln; + // This has to be done manually since we need it inside the float + OutputParams::CtObject ctobject = runparams.ctObject; + runparams.ctObject = OutputParams::CT_DISPLAYOBJECT; + Changes::latexMarkChange(os, buffer().params(), Change(Change::UNCHANGED), + Change(Change::DELETED), runparams); + runparams.ctObject = ctobject; } string alignment = getAlignment(); @@ -454,7 +460,7 @@ void InsetFloat::latex(otexstream & os, OutputParams const & runparams_in) const InsetText::latex(os, runparams); if (runparams.inDeletedInset) - os << "}}"; + os << "}"; // Force \end{} to appear in a new line. os << breakln << "\\end{" << from_ascii(tmptype) << "}\n"; diff --git a/src/insets/InsetFloat.h b/src/insets/InsetFloat.h index 734ba515ba..53c584c40a 100644 --- a/src/insets/InsetFloat.h +++ b/src/insets/InsetFloat.h @@ -122,6 +122,8 @@ private: TexString getCaption(OutputParams const &) const; /// std::string getAlignment() const; + /// + OutputParams::CtObject CtObject(OutputParams const &) const { return OutputParams::CT_OMITOBJECT; } InsetFloatParams params_; }; diff --git a/src/insets/InsetGraphics.cpp b/src/insets/InsetGraphics.cpp index 27df512a29..92de4c043f 100644 --- a/src/insets/InsetGraphics.cpp +++ b/src/insets/InsetGraphics.cpp @@ -858,11 +858,6 @@ void InsetGraphics::latex(otexstream & os, if (runparams.moving_arg) before += "\\protect"; - if (runparams.inDeletedInset) { - before += "\\lyxobjectsout{"; - after += "}"; - } - // We never use the starred form, we use the "clip" option instead. before += "\\includegraphics"; @@ -1141,8 +1136,10 @@ void InsetGraphics::validate(LaTeXFeatures & features) const if (contains(rel_file, ".")) features.require("lyxdot"); } - if (features.inDeletedInset()) + if (features.inDeletedInset()) { + features.require("tikz"); features.require("ct-tikz-object-sout"); + } } diff --git a/src/insets/InsetGraphics.h b/src/insets/InsetGraphics.h index b5fc5c830d..22d70b233b 100644 --- a/src/insets/InsetGraphics.h +++ b/src/insets/InsetGraphics.h @@ -133,6 +133,8 @@ private: /// \return the new filename, relative to the location of the HTML file, /// or an empty string on error. std::string prepareHTMLFile(OutputParams const & runparams) const; + /// + OutputParams::CtObject CtObject(OutputParams const &) const { return OutputParams::CT_OBJECT; } /// InsetGraphicsParams params_; diff --git a/src/mathed/InsetMathHull.cpp b/src/mathed/InsetMathHull.cpp index 8546a02253..9d4c0e556e 100644 --- a/src/mathed/InsetMathHull.cpp +++ b/src/mathed/InsetMathHull.cpp @@ -123,13 +123,10 @@ namespace { // writes a preamble for underlined or struck out math display void writeMathdisplayPreamble(WriteStream & os) { - if (os.strikeoutMath()) { - if (os.ulemCmd() == WriteStream::UNDERLINE) - os << "\\raisebox{-\\belowdisplayshortskip}{" - "\\lyxobjectsout{\\parbox[b]{\\linewidth}{"; - else - os << "\\lyxobjectsout{\\parbox{\\linewidth}{"; - } else if (os.ulemCmd() == WriteStream::UNDERLINE) + if (os.strikeoutMath()) + return; + + if (os.ulemCmd() == WriteStream::UNDERLINE) os << "\\raisebox{-\\belowdisplayshortskip}{" "\\parbox[b]{\\linewidth}{"; else if (os.ulemCmd() == WriteStream::STRIKEOUT) @@ -140,11 +137,10 @@ namespace { // writes a postamble for underlined or struck out math display void writeMathdisplayPostamble(WriteStream & os) { - if (os.strikeoutMath()) { - if (os.ulemCmd() == WriteStream::UNDERLINE) - os << "}"; - os << "}}\\\\\n"; - } else if (os.ulemCmd() == WriteStream::UNDERLINE) + if (os.strikeoutMath()) + return; + + if (os.ulemCmd() == WriteStream::UNDERLINE) os << "}}\\\\\n"; else if (os.ulemCmd() == WriteStream::STRIKEOUT) os << "}\\\\\n"; @@ -1104,6 +1100,7 @@ void InsetMathHull::validate(LaTeXFeatures & features) const from_ascii("\\newcommand{\\endregexp}{}")); } else if (outerDisplay() && features.inDeletedInset() && !features.mustProvide("ct-dvipost")) { + features.require("tikz"); features.require("ct-tikz-object-sout"); } @@ -1127,6 +1124,37 @@ void InsetMathHull::validate(LaTeXFeatures & features) const } +OutputParams::CtObject InsetMathHull::CtObject(OutputParams const & runparams) const +{ + OutputParams::CtObject res = OutputParams::CT_NORMAL; + switch(type_) { + case hullNone: + case hullSimple: + case hullAlignAt: + case hullXAlignAt: + case hullXXAlignAt: + case hullRegexp: + case hullUnknown: + break; + + case hullEquation: + case hullEqnArray: + case hullAlign: + case hullFlAlign: + case hullGather: + case hullMultline: { + if (runparams.inulemcmd + && (!runparams.local_font || runparams.local_font->fontInfo().strikeout() != FONT_ON)) + res = OutputParams::CT_UDISPLAYOBJECT; + else + res = OutputParams::CT_DISPLAYOBJECT; + break; + } + } + return res; +} + + void InsetMathHull::header_write(WriteStream & os) const { bool n = numberedType(); diff --git a/src/mathed/InsetMathHull.h b/src/mathed/InsetMathHull.h index c801a4f936..672685d0ba 100644 --- a/src/mathed/InsetMathHull.h +++ b/src/mathed/InsetMathHull.h @@ -88,6 +88,8 @@ public: /// bool outerDisplay() const; /// + OutputParams::CtObject CtObject(OutputParams const &) const; + /// void validate(LaTeXFeatures & features) const; /// identifies HullInset InsetMathHull const * asHullInset() const { return this; } diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 626311f17e..8c0d73e8c0 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -4051,7 +4051,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, continue; } - if (t.cs() == "lyxadded" || t.cs() == "lyxdeleted") { + if (t.cs() == "lyxadded" || t.cs() == "lyxdeleted" || t.cs() == "lyxobjdeleted" + || t.cs() == "lyxdisplayobjdeleted" || t.cs() == "lyxudisplayobjdeleted") { context.check_layout(os); string initials; if (p.hasOpt()) {