2 * \file InsetMathHull.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS.
13 #include "InsetMathHull.h"
15 #include "InsetMathChar.h"
16 #include "InsetMathColor.h"
17 #include "MathExtern.h"
18 #include "MathFactory.h"
19 #include "MathStream.h"
20 #include "MathSupport.h"
23 #include "BufferParams.h"
24 #include "BufferView.h"
25 #include "CutAndPaste.h"
27 #include "FuncRequest.h"
28 #include "FuncStatus.h"
29 #include "LaTeXFeatures.h"
32 #include "TextPainter.h"
33 #include "TocBackend.h"
35 #include "insets/InsetLabel.h"
36 #include "insets/InsetRef.h"
37 #include "insets/RenderPreview.h"
39 #include "graphics/PreviewImage.h"
41 #include "frontends/Painter.h"
43 #include "support/lassert.h"
44 #include "support/debug.h"
45 #include "support/gettext.h"
46 #include "support/lstrings.h"
51 using namespace lyx::support
;
55 using cap::grabAndEraseSelection
;
59 int getCols(HullType type
)
76 // returns position of first relation operator in the array
77 // used for "intelligent splitting"
78 size_t firstRelOp(MathData
const & ar
)
80 for (MathData::const_iterator it
= ar
.begin(); it
!= ar
.end(); ++it
)
82 return it
- ar
.begin();
87 char const * star(bool numbered
)
89 return numbered
? "" : "*";
93 } // end anon namespace
96 HullType
hullType(docstring
const & s
)
98 if (s
== "none") return hullNone
;
99 if (s
== "simple") return hullSimple
;
100 if (s
== "equation") return hullEquation
;
101 if (s
== "eqnarray") return hullEqnArray
;
102 if (s
== "align") return hullAlign
;
103 if (s
== "alignat") return hullAlignAt
;
104 if (s
== "xalignat") return hullXAlignAt
;
105 if (s
== "xxalignat") return hullXXAlignAt
;
106 if (s
== "multline") return hullMultline
;
107 if (s
== "gather") return hullGather
;
108 if (s
== "flalign") return hullFlAlign
;
109 if (s
== "regexp") return hullRegexp
;
110 lyxerr
<< "unknown hull type '" << to_utf8(s
) << "'" << endl
;
115 docstring
hullName(HullType type
)
118 case hullNone
: return from_ascii("none");
119 case hullSimple
: return from_ascii("simple");
120 case hullEquation
: return from_ascii("equation");
121 case hullEqnArray
: return from_ascii("eqnarray");
122 case hullAlign
: return from_ascii("align");
123 case hullAlignAt
: return from_ascii("alignat");
124 case hullXAlignAt
: return from_ascii("xalignat");
125 case hullXXAlignAt
: return from_ascii("xxalignat");
126 case hullMultline
: return from_ascii("multline");
127 case hullGather
: return from_ascii("gather");
128 case hullFlAlign
: return from_ascii("flalign");
129 case hullRegexp
: return from_ascii("regexp");
131 lyxerr
<< "unknown hull type '" << type
<< "'" << endl
;
132 return from_ascii("none");
136 static InsetLabel
* dummy_pointer
= 0;
138 InsetMathHull::InsetMathHull(Buffer
* buf
)
139 : InsetMathGrid(buf
, 1, 1), type_(hullNone
), nonum_(1, false),
140 label_(1, dummy_pointer
), preview_(new RenderPreview(this))
142 //lyxerr << "sizeof InsetMath: " << sizeof(InsetMath) << endl;
143 //lyxerr << "sizeof MetricsInfo: " << sizeof(MetricsInfo) << endl;
144 //lyxerr << "sizeof InsetMathChar: " << sizeof(InsetMathChar) << endl;
145 //lyxerr << "sizeof FontInfo: " << sizeof(FontInfo) << endl;
152 InsetMathHull::InsetMathHull(Buffer
* buf
, HullType type
)
153 : InsetMathGrid(buf
, getCols(type
), 1), type_(type
), nonum_(1, false),
154 label_(1, dummy_pointer
), preview_(new RenderPreview(this))
162 InsetMathHull::InsetMathHull(InsetMathHull
const & other
) : InsetMathGrid(other
)
168 InsetMathHull::~InsetMathHull()
170 for (size_t i
= 0; i
< label_
.size(); ++i
)
175 Inset
* InsetMathHull::clone() const
177 return new InsetMathHull(*this);
181 InsetMathHull
& InsetMathHull::operator=(InsetMathHull
const & other
)
185 InsetMathGrid::operator=(other
);
187 nonum_
= other
.nonum_
;
188 buffer_
= other
.buffer_
;
189 for (size_t i
= 0; i
< label_
.size(); ++i
)
191 label_
= other
.label_
;
192 for (size_t i
= 0; i
!= label_
.size(); ++i
) {
194 label_
[i
] = new InsetLabel(*label_
[i
]);
196 preview_
.reset(new RenderPreview(*other
.preview_
, this));
202 void InsetMathHull::setBuffer(Buffer
& buffer
)
204 InsetMathGrid::setBuffer(buffer
);
206 for (size_t i
= 0; i
!= label_
.size(); ++i
) {
208 label_
[i
]->setBuffer(buffer
);
213 void InsetMathHull::updateLabels(ParIterator
const & it
)
216 //FIXME: buffer_ should be set at creation for this inset! Problem is
217 // This inset is created at too many places (see Parser::parse1() in
221 for (size_t i
= 0; i
!= label_
.size(); ++i
) {
223 label_
[i
]->updateLabels(it
);
228 void InsetMathHull::addToToc(DocIterator
const & pit
)
231 //FIXME: buffer_ should be set at creation for this inset! Problem is
232 // This inset is created at too many places (see Parser::parse1() in
237 Toc
& toc
= buffer().tocBackend().toc("equation");
239 for (row_type row
= 0; row
!= nrows(); ++row
) {
243 label_
[row
]->addToToc(pit
);
244 toc
.push_back(TocItem(pit
, 0, nicelabel(row
)));
249 Inset
* InsetMathHull::editXY(Cursor
& cur
, int x
, int y
)
255 return InsetMathNest::editXY(cur
, x
, y
);
259 InsetMath::mode_type
InsetMathHull::currentMode() const
261 if (type_
== hullNone
)
262 return UNDECIDED_MODE
;
263 // definitely math mode ...
268 bool InsetMathHull::idxFirst(Cursor
& cur
) const
276 bool InsetMathHull::idxLast(Cursor
& cur
) const
278 cur
.idx() = nargs() - 1;
279 cur
.pos() = cur
.lastpos();
284 char InsetMathHull::defaultColAlign(col_type col
)
286 if (type_
== hullEqnArray
)
288 if (type_
== hullGather
)
290 if (type_
>= hullAlign
)
291 return "rl"[col
& 1];
296 int InsetMathHull::defaultColSpace(col_type col
)
298 if (type_
== hullAlign
|| type_
== hullAlignAt
)
300 if (type_
== hullXAlignAt
)
301 return (col
& 1) ? 20 : 0;
302 if (type_
== hullXXAlignAt
|| type_
== hullFlAlign
)
303 return (col
& 1) ? 40 : 0;
308 docstring
InsetMathHull::standardFont() const
310 return from_ascii(type_
== hullNone
? "lyxnochange" : "mathnormal");
314 bool InsetMathHull::previewState(BufferView
* bv
) const
316 if (!editing(bv
) && RenderPreview::status() == LyXRC::PREVIEW_ON
) {
317 graphics::PreviewImage
const * pimage
=
318 preview_
->getPreviewImage(bv
->buffer());
319 return pimage
&& pimage
->image();
325 void InsetMathHull::metrics(MetricsInfo
& mi
, Dimension
& dim
) const
327 if (previewState(mi
.base
.bv
)) {
328 preview_
->metrics(mi
, dim
);
329 // insert a one pixel gap in front of the formula
332 dim
.des
+= displayMargin();
333 // Cache the inset dimension.
334 setDimCache(mi
, dim
);
338 FontSetChanger
dummy1(mi
.base
, standardFont());
339 StyleChanger
dummy2(mi
.base
, display() ? LM_ST_DISPLAY
: LM_ST_TEXT
);
341 // let the cells adjust themselves
342 InsetMathGrid::metrics(mi
, dim
);
345 dim
.asc
+= displayMargin();
346 dim
.des
+= displayMargin();
349 if (numberedType()) {
350 FontSetChanger
dummy(mi
.base
, from_ascii("mathbf"));
352 for (row_type row
= 0; row
< nrows(); ++row
)
353 l
= max(l
, mathed_string_width(mi
.base
.font
, nicelabel(row
)));
359 // make it at least as high as the current font
362 math_font_max_dim(mi
.base
.font
, asc
, des
);
363 dim
.asc
= max(dim
.asc
, asc
);
364 dim
.des
= max(dim
.des
, des
);
365 // Cache the inset dimension.
366 // FIXME: This will overwrite InsetMathGrid dimension, is that OK?
367 setDimCache(mi
, dim
);
371 void InsetMathHull::drawBackground(PainterInfo
& pi
, int x
, int y
) const
373 Dimension
const dim
= dimension(*pi
.base
.bv
);
374 pi
.pain
.fillRectangle(x
+ 1, y
- dim
.asc
+ 1, dim
.wid
- 2,
375 dim
.asc
+ dim
.des
- 1, pi
.backgroundColor(this));
379 void InsetMathHull::draw(PainterInfo
& pi
, int x
, int y
) const
381 use_preview_
= previewState(pi
.base
.bv
);
384 // one pixel gap in front
385 preview_
->draw(pi
, x
+ 1, y
);
386 setPosCache(pi
, x
, y
);
390 FontSetChanger
dummy1(pi
.base
, standardFont());
391 StyleChanger
dummy2(pi
.base
, display() ? LM_ST_DISPLAY
: LM_ST_TEXT
);
392 InsetMathGrid::draw(pi
, x
+ 1, y
);
394 if (numberedType()) {
395 int const xx
= x
+ colinfo_
.back().offset_
+ colinfo_
.back().width_
+ 20;
396 for (row_type row
= 0; row
< nrows(); ++row
) {
397 int const yy
= y
+ rowinfo_
[row
].offset_
;
398 FontSetChanger
dummy(pi
.base
, from_ascii("mathrm"));
399 docstring
const nl
= nicelabel(row
);
403 setPosCache(pi
, x
, y
);
407 void InsetMathHull::metricsT(TextMetricsInfo
const & mi
, Dimension
& dim
) const
410 InsetMathGrid::metricsT(mi
, dim
);
413 WriteStream
wi(os
, false, true, WriteStream::wsDefault
);
415 dim
.wid
= os
.str().size();
422 void InsetMathHull::drawT(TextPainter
& pain
, int x
, int y
) const
425 InsetMathGrid::drawT(pain
, x
, y
);
428 WriteStream
wi(os
, false, true, WriteStream::wsDefault
);
430 pain
.draw(x
, y
, os
.str().c_str());
435 static docstring
latexString(InsetMathHull
const & inset
)
438 // This has to be static, because a preview snippet or a math
439 // macro containing math in text mode (such as $\text{$\phi$}$ or
440 // \newcommand{\xxx}{\text{$\phi$}}) gets processed twice. The
441 // first time as a whole, and the second time only the inner math.
442 // In this last case inset.buffer() would be invalid.
443 static Encoding
const * encoding
= 0;
444 if (inset
.isBufferValid())
445 encoding
= &(inset
.buffer().params().encoding());
446 WriteStream
wi(ls
, false, true, WriteStream::wsPreview
, encoding
);
452 void InsetMathHull::initUnicodeMath() const
454 // Trigger classification of the unicode symbols in this inset
455 docstring
const dummy
= latexString(*this);
459 void InsetMathHull::addPreview(graphics::PreviewLoader
& ploader
) const
461 if (RenderPreview::status() == LyXRC::PREVIEW_ON
) {
462 docstring
const snippet
= latexString(*this);
463 preview_
->addPreview(snippet
, ploader
);
468 bool InsetMathHull::notifyCursorLeaves(Cursor
const & /*old*/, Cursor
& cur
)
470 if (RenderPreview::status() == LyXRC::PREVIEW_ON
) {
471 Buffer
const * buffer
= cur
.buffer();
472 docstring
const snippet
= latexString(*this);
473 preview_
->addPreview(snippet
, *buffer
);
474 preview_
->startLoading(*buffer
);
475 cur
.updateFlags(Update::Force
);
481 docstring
InsetMathHull::label(row_type row
) const
483 LASSERT(row
< nrows(), /**/);
484 if (InsetLabel
* il
= label_
[row
])
485 return il
->screenLabel();
490 void InsetMathHull::label(row_type row
, docstring
const & label
)
492 //lyxerr << "setting label '" << label << "' for row " << row << endl;
496 label_
[row
] = dummy_pointer
;
497 // We need an update of the Buffer reference cache.
498 // This is achieved by updateLabels().
500 buffer().updateLabels();
503 label_
[row
]->updateCommand(label
);
505 label_
[row
]->setParam("name", label
);
509 InsetCommandParams
p(LABEL_CODE
);
511 label_
[row
] = new InsetLabel(buffer_
, p
);
513 label_
[row
]->setBuffer(buffer());
517 void InsetMathHull::numbered(row_type row
, bool num
)
520 if (nonum_
[row
] && label_
[row
]) {
524 // The buffer is set at the end of readInset.
525 // When parsing the inset, buffer_ is 0.
528 // We need an update of the Buffer reference cache.
529 // This is achieved by updateLabels().
530 buffer().updateLabels();
535 bool InsetMathHull::numbered(row_type row
) const
541 bool InsetMathHull::ams() const
543 return type_
== hullAlign
544 || type_
== hullFlAlign
545 || type_
== hullMultline
546 || type_
== hullGather
547 || type_
== hullAlignAt
548 || type_
== hullXAlignAt
549 || type_
== hullXXAlignAt
;
553 Inset::DisplayType
InsetMathHull::display() const
555 if (type_
== hullSimple
|| type_
== hullNone
|| type_
== hullRegexp
)
560 bool InsetMathHull::numberedType() const
562 if (type_
== hullNone
)
564 if (type_
== hullSimple
)
566 if (type_
== hullXXAlignAt
)
568 if (type_
== hullRegexp
)
570 for (row_type row
= 0; row
< nrows(); ++row
)
577 void InsetMathHull::validate(LaTeXFeatures
& features
) const
580 features
.require("amsmath");
582 // Validation is necessary only if not using AMS math.
583 // To be safe, we will always run mathedvalidate.
584 //if (features.amsstyle)
587 //features.binom = true;
589 InsetMathGrid::validate(features
);
593 void InsetMathHull::header_write(WriteStream
& os
) const
595 bool n
= numberedType();
609 os
<< "\\begin{equation" << star(n
) << "}\n";
619 os
<< "\\begin{" << hullName(type_
) << star(n
) << "}\n";
624 os
<< "\\begin{" << hullName(type_
) << star(n
) << '}'
625 << '{' << static_cast<unsigned int>((ncols() + 1)/2) << "}\n";
629 os
<< "\\begin{" << hullName(type_
) << '}'
630 << '{' << static_cast<unsigned int>((ncols() + 1)/2) << "}\n";
638 os
<< "\\begin{unknown" << star(n
) << '}';
644 void InsetMathHull::footer_write(WriteStream
& os
) const
646 bool n
= numberedType();
659 os
<< "\\end{equation" << star(n
) << "}\n";
671 os
<< "\\end{" << hullName(type_
) << star(n
) << "}\n";
675 os
<< "\\end{" << hullName(type_
) << "}\n";
683 os
<< "\\end{unknown" << star(n
) << '}';
689 bool InsetMathHull::rowChangeOK() const
692 type_
== hullEqnArray
|| type_
== hullAlign
||
693 type_
== hullFlAlign
|| type_
== hullAlignAt
||
694 type_
== hullXAlignAt
|| type_
== hullXXAlignAt
||
695 type_
== hullGather
|| type_
== hullMultline
;
699 bool InsetMathHull::colChangeOK() const
702 type_
== hullAlign
|| type_
== hullFlAlign
||type_
== hullAlignAt
||
703 type_
== hullXAlignAt
|| type_
== hullXXAlignAt
;
707 void InsetMathHull::addRow(row_type row
)
712 bool numbered
= numberedType();
714 if (type_
== hullMultline
) {
715 if (row
+ 1 == nrows()) {
722 nonum_
.insert(nonum_
.begin() + row
+ 1, !numbered
);
723 label_
.insert(label_
.begin() + row
+ 1, dummy_pointer
);
726 InsetMathGrid::addRow(row
);
730 void InsetMathHull::swapRow(row_type row
)
734 if (row
+ 1 == nrows())
736 // gcc implements the standard std::vector<bool> which is *not* a container:
737 // http://www.gotw.ca/publications/N1185.pdf
738 // As a results, it doesn't like this:
739 // swap(nonum_[row], nonum_[row + 1]);
740 // so we do it manually:
741 bool const b
= nonum_
[row
];
742 nonum_
[row
] = nonum_
[row
+ 1];
744 swap(label_
[row
], label_
[row
+ 1]);
745 InsetMathGrid::swapRow(row
);
749 void InsetMathHull::delRow(row_type row
)
751 if (nrows() <= 1 || !rowChangeOK())
753 if (row
+ 1 == nrows() && type_
== hullMultline
) {
754 bool const b
= nonum_
[row
- 1];
755 nonum_
[row
- 1] = nonum_
[row
];
757 swap(label_
[row
- 1], label_
[row
]);
758 InsetMathGrid::delRow(row
);
761 InsetMathGrid::delRow(row
);
762 // The last dummy row has no number info nor a label.
763 // Test nrows() + 1 because we have already erased the row.
764 if (row
== nrows() + 1)
766 nonum_
.erase(nonum_
.begin() + row
);
768 label_
.erase(label_
.begin() + row
);
772 void InsetMathHull::addCol(col_type col
)
776 InsetMathGrid::addCol(col
);
780 void InsetMathHull::delCol(col_type col
)
782 if (ncols() <= 1 || !colChangeOK())
784 InsetMathGrid::delCol(col
);
788 docstring
InsetMathHull::nicelabel(row_type row
) const
793 return from_ascii("(#)");
794 return '(' + label_
[row
]->screenLabel() + from_ascii(", #)");
798 void InsetMathHull::glueall()
801 for (idx_type i
= 0; i
< nargs(); ++i
)
803 *this = InsetMathHull(buffer_
, hullSimple
);
809 void InsetMathHull::splitTo2Cols()
811 LASSERT(ncols() == 1, /**/);
812 InsetMathGrid::addCol(1);
813 for (row_type row
= 0; row
< nrows(); ++row
) {
814 idx_type
const i
= 2 * row
;
815 pos_type pos
= firstRelOp(cell(i
));
816 cell(i
+ 1) = MathData(buffer_
, cell(i
).begin() + pos
, cell(i
).end());
817 cell(i
).erase(pos
, cell(i
).size());
822 void InsetMathHull::splitTo3Cols()
824 LASSERT(ncols() < 3, /**/);
827 InsetMathGrid::addCol(2);
828 for (row_type row
= 0; row
< nrows(); ++row
) {
829 idx_type
const i
= 3 * row
+ 1;
830 if (cell(i
).size()) {
831 cell(i
+ 1) = MathData(buffer_
, cell(i
).begin() + 1, cell(i
).end());
832 cell(i
).erase(1, cell(i
).size());
838 void InsetMathHull::changeCols(col_type cols
)
842 else if (ncols() < cols
) {
848 while (ncols() < cols
)
849 InsetMathGrid::addCol(ncols());
855 for (row_type row
= 0; row
< nrows(); ++row
) {
856 idx_type
const i
= row
* ncols();
857 for (col_type col
= cols
; col
< ncols(); ++col
) {
858 cell(i
+ cols
- 1).append(cell(i
+ col
));
862 while (ncols() > cols
) {
863 InsetMathGrid::delCol(ncols() - 1);
868 HullType
InsetMathHull::getType() const
874 void InsetMathHull::setType(HullType type
)
881 void InsetMathHull::mutate(HullType newtype
)
883 //lyxerr << "mutating from '" << type_ << "' to '" << newtype << "'" << endl;
885 // we try to move along the chain
886 // none <-> simple <-> equation <-> eqnarray -> *align* -> multline, gather -+
888 // +-------------------------------------+
889 // we use eqnarray as intermediate type for mutations that are not
890 // directly supported because it handles labels and numbering for
893 if (newtype
== type_
) {
897 else if (newtype
< hullNone
) {
902 else if (type_
== hullNone
) {
908 else if (type_
== hullSimple
) {
909 if (newtype
== hullNone
) {
913 setType(hullEquation
);
919 else if (type_
== hullEquation
) {
920 if (newtype
< type_
) {
924 } else if (newtype
== hullEqnArray
) {
925 // split it "nicely" on the first relop
927 setType(hullEqnArray
);
928 } else if (newtype
== hullMultline
|| newtype
== hullGather
) {
938 else if (type_
== hullEqnArray
) {
939 if (newtype
< type_
) {
940 // set correct (no)numbering
942 for (row_type row
= 0; row
< nrows(); ++row
) {
949 // set first non-empty label
950 for (row_type row
= 0; row
< nrows(); ++row
) {
952 label_
[0] = label_
[row
];
959 } else { // align & Co.
966 else if (type_
== hullAlign
|| type_
== hullAlignAt
||
967 type_
== hullXAlignAt
|| type_
== hullFlAlign
) {
968 if (newtype
< hullAlign
) {
970 setType(hullEqnArray
);
972 } else if (newtype
== hullGather
|| newtype
== hullMultline
) {
975 } else if (newtype
== hullXXAlignAt
) {
976 for (row_type row
= 0; row
< nrows(); ++row
)
977 numbered(row
, false);
984 else if (type_
== hullXXAlignAt
) {
985 for (row_type row
= 0; row
< nrows(); ++row
)
986 numbered(row
, false);
987 if (newtype
< hullAlign
) {
989 setType(hullEqnArray
);
991 } else if (newtype
== hullGather
|| newtype
== hullMultline
) {
999 else if (type_
== hullMultline
|| type_
== hullGather
) {
1000 if (newtype
== hullGather
|| newtype
== hullMultline
)
1002 else if (newtype
== hullAlign
|| newtype
== hullFlAlign
||
1003 newtype
== hullAlignAt
|| newtype
== hullXAlignAt
) {
1006 } else if (newtype
== hullXXAlignAt
) {
1008 for (row_type row
= 0; row
< nrows(); ++row
)
1009 numbered(row
, false);
1013 setType(hullEqnArray
);
1019 lyxerr
<< "mutation from '" << to_utf8(hullName(type_
))
1020 << "' to '" << to_utf8(hullName(newtype
))
1021 << "' not implemented" << endl
;
1026 docstring
InsetMathHull::eolString(row_type row
, bool fragile
) const
1029 if (numberedType()) {
1030 if (label_
[row
] && !nonum_
[row
])
1031 res
+= "\\label{" + label_
[row
]->getParam("name") + '}';
1032 if (nonum_
[row
] && (type_
!= hullMultline
))
1033 res
+= "\\nonumber ";
1035 return res
+ InsetMathGrid::eolString(row
, fragile
);
1039 void InsetMathHull::write(WriteStream
& os
) const
1041 ModeSpecifier
specifier(os
, MATH_MODE
);
1043 InsetMathGrid::write(os
);
1048 void InsetMathHull::normalize(NormalStream
& os
) const
1050 os
<< "[formula " << hullName(type_
) << ' ';
1051 InsetMathGrid::normalize(os
);
1056 void InsetMathHull::mathmlize(MathStream
& os
) const
1058 InsetMathGrid::mathmlize(os
);
1062 void InsetMathHull::infoize(odocstream
& os
) const
1064 os
<< "Type: " << hullName(type_
);
1068 void InsetMathHull::check() const
1070 LASSERT(nonum_
.size() == nrows(), /**/);
1071 LASSERT(label_
.size() == nrows(), /**/);
1075 void InsetMathHull::doExtern(Cursor
& cur
, FuncRequest
& func
)
1079 idocstringstream
iss(func
.argument());
1080 iss
>> dlang
>> extra
;
1082 extra
= from_ascii("noextra");
1083 string
const lang
= to_ascii(dlang
);
1085 // FIXME: temporarily disabled
1086 //if (cur.selection()) {
1089 // lyxerr << "use selection: " << ar << endl;
1090 // insert(pipeThroughExtern(lang, extra, ar));
1095 eq
.push_back(MathAtom(new InsetMathChar('=')));
1097 // go to first item in line
1098 cur
.idx() -= cur
.idx() % ncols();
1101 if (getType() == hullSimple
) {
1102 size_type pos
= cur
.cell().find_last(eq
);
1104 if (cur
.inMathed() && cur
.selection()) {
1105 asArray(grabAndEraseSelection(cur
), ar
);
1106 } else if (pos
== cur
.cell().size()) {
1108 lyxerr
<< "use whole cell: " << ar
<< endl
;
1110 ar
= MathData(buffer_
, cur
.cell().begin() + pos
+ 1, cur
.cell().end());
1111 lyxerr
<< "use partial cell form pos: " << pos
<< endl
;
1113 cur
.cell().append(eq
);
1114 cur
.cell().append(pipeThroughExtern(lang
, extra
, ar
));
1115 cur
.pos() = cur
.lastpos();
1119 if (getType() == hullEquation
) {
1120 lyxerr
<< "use equation inset" << endl
;
1121 mutate(hullEqnArray
);
1122 MathData
& ar
= cur
.cell();
1123 lyxerr
<< "use cell: " << ar
<< endl
;
1127 cur
.cell() = pipeThroughExtern(lang
, extra
, ar
);
1128 // move to end of line
1129 cur
.pos() = cur
.lastpos();
1134 lyxerr
<< "use eqnarray" << endl
;
1135 cur
.idx() += 2 - cur
.idx() % ncols();
1137 MathData ar
= cur
.cell();
1138 lyxerr
<< "use cell: " << ar
<< endl
;
1139 // FIXME: temporarily disabled
1145 cur
.cell() = pipeThroughExtern(lang
, extra
, ar
);
1146 cur
.pos() = cur
.lastpos();
1151 void InsetMathHull::doDispatch(Cursor
& cur
, FuncRequest
& cmd
)
1153 //lyxerr << "action: " << cmd.action << endl;
1154 switch (cmd
.action
) {
1156 case LFUN_FINISHED_BACKWARD
:
1157 case LFUN_FINISHED_FORWARD
:
1158 case LFUN_FINISHED_RIGHT
:
1159 case LFUN_FINISHED_LEFT
:
1160 //lyxerr << "action: " << cmd.action << endl;
1161 InsetMathGrid::doDispatch(cur
, cmd
);
1165 case LFUN_BREAK_PARAGRAPH
:
1166 // just swallow this
1169 case LFUN_NEWLINE_INSERT
:
1170 // some magic for the common case
1171 if (type_
== hullSimple
|| type_
== hullEquation
) {
1172 cur
.recordUndoInset();
1174 cur
.bv().buffer().params().use_amsmath
== BufferParams::package_on
;
1175 mutate(align
? hullAlign
: hullEqnArray
);
1176 cur
.idx() = nrows() * ncols() - 1;
1177 cur
.pos() = cur
.lastpos();
1179 InsetMathGrid::doDispatch(cur
, cmd
);
1182 case LFUN_MATH_NUMBER_TOGGLE
: {
1183 //lyxerr << "toggling all numbers" << endl;
1184 cur
.recordUndoInset();
1185 bool old
= numberedType();
1186 if (type_
== hullMultline
)
1187 numbered(nrows() - 1, !old
);
1189 for (row_type row
= 0; row
< nrows(); ++row
)
1190 numbered(row
, !old
);
1192 cur
.message(old
? _("No number") : _("Number"));
1196 case LFUN_MATH_NUMBER_LINE_TOGGLE
: {
1197 cur
.recordUndoInset();
1198 row_type r
= (type_
== hullMultline
) ? nrows() - 1 : cur
.row();
1199 bool old
= numbered(r
);
1200 cur
.message(old
? _("No number") : _("Number"));
1205 case LFUN_LABEL_INSERT
: {
1206 cur
.recordUndoInset();
1207 row_type r
= (type_
== hullMultline
) ? nrows() - 1 : cur
.row();
1208 docstring old_label
= label(r
);
1209 docstring
const default_label
= from_ascii(
1210 (lyxrc
.label_init_length
>= 0) ? "eq:" : "");
1211 if (old_label
.empty())
1212 old_label
= default_label
;
1214 InsetCommandParams
p(LABEL_CODE
);
1215 p
["name"] = cmd
.argument().empty() ? old_label
: cmd
.argument();
1216 string
const data
= InsetCommand::params2string("label", p
);
1218 if (cmd
.argument().empty())
1219 cur
.bv().showDialog("label", data
);
1221 FuncRequest
fr(LFUN_INSET_INSERT
, data
);
1227 case LFUN_LABEL_COPY_AS_REF
: {
1229 if (cmd
.argument().empty() && &cur
.inset() == this)
1230 // if there is no argument and we're inside math, we retrieve
1231 // the row number from the cursor position.
1232 row
= (type_
== hullMultline
) ? nrows() - 1 : cur
.row();
1234 // if there is an argument, find the corresponding label, else
1235 // check whether there is at least one label.
1236 for (row
= 0; row
!= nrows(); ++row
)
1237 if (!nonum_
[row
] && label_
[row
]
1238 && (cmd
.argument().empty() || label(row
) == cmd
.argument()))
1245 InsetCommandParams
p(REF_CODE
, "ref");
1246 p
["reference"] = label(row
);
1247 cap::clearSelection();
1248 cap::copyInset(cur
, new InsetRef(buffer_
, p
), label(row
));
1252 case LFUN_WORD_DELETE_FORWARD
:
1253 case LFUN_CHAR_DELETE_FORWARD
:
1254 if (col(cur
.idx()) + 1 == ncols()
1255 && cur
.pos() == cur
.lastpos()
1256 && !cur
.selection()) {
1257 if (!label(row(cur
.idx())).empty()) {
1258 cur
.recordUndoInset();
1259 label(row(cur
.idx()), docstring());
1260 } else if (numbered(row(cur
.idx()))) {
1261 cur
.recordUndoInset();
1262 numbered(row(cur
.idx()), false);
1264 InsetMathGrid::doDispatch(cur
, cmd
);
1268 InsetMathGrid::doDispatch(cur
, cmd
);
1273 case LFUN_INSET_INSERT
: {
1274 //lyxerr << "arg: " << to_utf8(cmd.argument()) << endl;
1275 // FIXME: this should be cleaned up to use InsetLabel methods directly.
1276 string
const name
= cmd
.getArg(0);
1277 if (name
== "label") {
1278 InsetCommandParams
p(LABEL_CODE
);
1279 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), p
);
1280 docstring str
= p
["name"];
1281 cur
.recordUndoInset();
1282 row_type
const r
= (type_
== hullMultline
) ? nrows() - 1 : cur
.row();
1286 docstring old
= label(r
);
1289 // The label will take care of the reference update.
1293 // Newly created inset so initialize it.
1294 label_
[r
]->initView();
1299 InsetMathGrid::doDispatch(cur
, cmd
);
1303 case LFUN_MATH_EXTERN
:
1304 cur
.recordUndoInset();
1308 case LFUN_MATH_MUTATE
: {
1309 cur
.recordUndoInset();
1310 row_type row
= cur
.row();
1311 col_type col
= cur
.col();
1312 mutate(hullType(cmd
.argument()));
1313 cur
.idx() = row
* ncols() + col
;
1314 if (cur
.idx() > cur
.lastidx()) {
1315 cur
.idx() = cur
.lastidx();
1316 cur
.pos() = cur
.lastpos();
1318 if (cur
.pos() > cur
.lastpos())
1319 cur
.pos() = cur
.lastpos();
1321 // FIXME: find some more clever handling of the selection,
1322 // i.e. preserve it.
1323 cur
.clearSelection();
1324 //cur.dispatched(FINISHED);
1328 case LFUN_MATH_DISPLAY
: {
1329 cur
.recordUndoInset();
1330 mutate(type_
== hullSimple
? hullEquation
: hullSimple
);
1332 cur
.pos() = cur
.lastpos();
1333 //cur.dispatched(FINISHED);
1338 InsetMathGrid::doDispatch(cur
, cmd
);
1344 bool InsetMathHull::getStatus(Cursor
& cur
, FuncRequest
const & cmd
,
1345 FuncStatus
& status
) const
1347 switch (cmd
.action
) {
1348 case LFUN_FINISHED_BACKWARD
:
1349 case LFUN_FINISHED_FORWARD
:
1350 case LFUN_FINISHED_RIGHT
:
1351 case LFUN_FINISHED_LEFT
:
1354 case LFUN_NEWLINE_INSERT
:
1355 case LFUN_MATH_EXTERN
:
1356 case LFUN_MATH_DISPLAY
:
1358 status
.setEnabled(true);
1361 case LFUN_MATH_MUTATE
: {
1362 HullType ht
= hullType(cmd
.argument());
1363 status
.setOnOff(type_
== ht
);
1364 status
.setEnabled(true);
1368 case LFUN_MATH_NUMBER_TOGGLE
:
1369 // FIXME: what is the right test, this or the one of
1371 status
.setEnabled(display());
1372 status
.setOnOff(numberedType());
1375 case LFUN_MATH_NUMBER_LINE_TOGGLE
: {
1376 // FIXME: what is the right test, this or the one of
1378 bool const enable
= (type_
== hullMultline
)
1379 ? (nrows() - 1 == cur
.row())
1380 : display() != Inline
&& nrows() > 1;
1381 row_type
const r
= (type_
== hullMultline
) ? nrows() - 1 : cur
.row();
1382 status
.setEnabled(enable
);
1383 status
.setOnOff(enable
&& numbered(r
));
1387 case LFUN_LABEL_INSERT
:
1388 status
.setEnabled(type_
!= hullSimple
);
1391 case LFUN_LABEL_COPY_AS_REF
: {
1392 bool enabled
= false;
1394 if (cmd
.argument().empty() && &cur
.inset() == this) {
1395 // if there is no argument and we're inside math, we retrieve
1396 // the row number from the cursor position.
1397 row
= (type_
== hullMultline
) ? nrows() - 1 : cur
.row();
1398 enabled
= numberedType() && label_
[row
] && !nonum_
[row
];
1400 // if there is an argument, find the corresponding label, else
1401 // check whether there is at least one label.
1402 for (row_type row
= 0; row
!= nrows(); ++row
) {
1403 if (!nonum_
[row
] && label_
[row
] &&
1404 (cmd
.argument().empty() || label(row
) == cmd
.argument())) {
1410 status
.setEnabled(enabled
);
1414 case LFUN_INSET_INSERT
:
1415 if (cmd
.getArg(0) == "label") {
1416 status
.setEnabled(type_
!= hullSimple
);
1419 return InsetMathGrid::getStatus(cur
, cmd
, status
);
1421 case LFUN_TABULAR_FEATURE
: {
1422 istringstream
is(to_utf8(cmd
.argument()));
1426 && (s
== "append-row"
1427 || s
== "delete-row"
1428 || s
== "copy-row")) {
1429 status
.message(bformat(
1430 from_utf8(N_("Can't change number of rows in '%1$s'")),
1432 status
.setEnabled(false);
1436 && (s
== "append-column"
1437 || s
== "delete-column"
1438 || s
== "copy-column")) {
1439 status
.message(bformat(
1440 from_utf8(N_("Can't change number of columns in '%1$s'")),
1442 status
.setEnabled(false);
1445 if ((type_
== hullSimple
1446 || type_
== hullEquation
1447 || type_
== hullNone
) &&
1448 (s
== "add-hline-above" || s
== "add-hline-below")) {
1449 status
.message(bformat(
1450 from_utf8(N_("Can't add horizontal grid lines in '%1$s'")),
1452 status
.setEnabled(false);
1455 if (s
== "add-vline-left" || s
== "add-vline-right") {
1456 status
.message(bformat(
1457 from_utf8(N_("Can't add vertical grid lines in '%1$s'")),
1459 status
.setEnabled(false);
1462 if (s
== "valign-top" || s
== "valign-middle"
1463 || s
== "valign-bottom" || s
== "align-left"
1464 || s
== "align-center" || s
== "align-right") {
1465 status
.setEnabled(false);
1468 return InsetMathGrid::getStatus(cur
, cmd
, status
);
1472 return InsetMathGrid::getStatus(cur
, cmd
, status
);
1475 // This cannot really happen, but inserted to shut-up gcc
1476 return InsetMathGrid::getStatus(cur
, cmd
, status
);
1480 /////////////////////////////////////////////////////////////////////
1484 // simply scrap this function if you want
1485 void InsetMathHull::mutateToText()
1488 // translate to latex
1490 latex(os
, false, false);
1491 string str
= os
.str();
1494 Text
* lt
= view_
->cursor().innerText();
1495 string::const_iterator cit
= str
.begin();
1496 string::const_iterator end
= str
.end();
1497 for (; cit
!= end
; ++cit
)
1498 view_
->getIntl()->getTransManager().TranslateAndInsert(*cit
, lt
);
1501 //dispatch(LFUN_ESCAPE);
1506 void InsetMathHull::handleFont(Cursor
& cur
, docstring
const & arg
,
1507 docstring
const & font
)
1509 // this whole function is a hack and won't work for incremental font
1512 if (cur
.inset().asInsetMath()->name() == font
)
1513 cur
.handleFont(to_utf8(font
));
1515 cur
.handleNest(createInsetMath(font
, cur
.buffer()));
1521 void InsetMathHull::handleFont2(Cursor
& cur
, docstring
const & arg
)
1526 font
.fromString(to_utf8(arg
), b
);
1527 if (font
.fontInfo().color() != Color_inherit
) {
1528 MathAtom at
= MathAtom(new InsetMathColor(buffer_
, true, font
.fontInfo().color()));
1529 cur
.handleNest(at
, 0);
1534 void InsetMathHull::edit(Cursor
& cur
, bool front
, EntryDirection entry_from
)
1537 bool enter_front
= (entry_from
== Inset::ENTRY_DIRECTION_LEFT
||
1538 (entry_from
== Inset::ENTRY_DIRECTION_IGNORE
&& front
));
1539 enter_front
? idxFirst(cur
) : idxLast(cur
);
1540 // The inset formula dimension is not necessarily the same as the
1541 // one of the instant preview image, so we have to indicate to the
1542 // BufferView that a metrics update is needed.
1543 cur
.updateFlags(Update::Force
);
1547 void InsetMathHull::revealCodes(Cursor
& cur
) const
1549 if (!cur
.inMathed())
1551 odocstringstream os
;
1553 cur
.message(os
.str());
1555 // write something to the minibuffer
1556 // translate to latex
1560 string str = os.str();
1562 string::size_type pos = 0;
1564 for (string::iterator it = str.begin(); it != str.end(); ++it) {
1567 else if (*it == '\0') {
1569 pos = it - str.begin();
1575 res = res.substr(pos - 30);
1576 if (res.size() > 60)
1577 res = res.substr(0, 60);
1583 /////////////////////////////////////////////////////////////////////
1587 bool InsetMathHull::searchForward(BufferView
* bv
, string
const & str
,
1590 // FIXME: completely broken
1591 static InsetMathHull
* lastformula
= 0;
1592 static CursorBase current
= DocIterator(ibegin(nucleus()));
1594 static string laststr
;
1596 if (lastformula
!= this || laststr
!= str
) {
1597 //lyxerr << "reset lastformula to " << this << endl;
1600 current
= ibegin(nucleus());
1602 mathed_parse_cell(ar
, str
, Parse::NORMAL
, &buffer());
1606 //lyxerr << "searching '" << str << "' in " << this << ar << endl;
1608 for (DocIterator it
= current
; it
!= iend(nucleus()); increment(it
)) {
1609 CursorSlice
& top
= it
.back();
1610 MathData
const & a
= top
.asInsetMath()->cell(top
.idx_
);
1611 if (a
.matchpart(ar
, top
.pos_
)) {
1612 bv
->cursor().setSelection(it
, ar
.size());
1614 top
.pos_
+= ar
.size();
1620 //lyxerr << "not found!" << endl;
1627 void InsetMathHull::write(ostream
& os
) const
1629 odocstringstream oss
;
1630 WriteStream
wi(oss
, false, false, WriteStream::wsDefault
);
1633 os
<< to_utf8(oss
.str());
1637 void InsetMathHull::read(Lexer
& lex
)
1640 mathed_parse_normal(buffer_
, at
, lex
, Parse::TRACKMACRO
);
1641 operator=(*at
->asHullInset());
1645 bool InsetMathHull::readQuiet(Lexer
& lex
)
1648 bool success
= mathed_parse_normal(buffer_
, at
, lex
, Parse::QUIET
);
1650 operator=(*at
->asHullInset());
1655 int InsetMathHull::plaintext(odocstream
& os
, OutputParams
const &) const
1657 if (0 && display()) {
1661 TextPainter
tpain(dim
.width(), dim
.height());
1662 drawT(tpain
, 0, dim
.ascent());
1664 // reset metrics cache to "real" values
1666 return tpain
.textheight();
1668 odocstringstream oss
;
1669 Encoding
const * const enc
= encodings
.fromLyXName("utf8");
1670 WriteStream
wi(oss
, false, true, WriteStream::wsDefault
, enc
);
1672 if (type_
== hullRegexp
)
1676 docstring
const str
= oss
.str();
1683 int InsetMathHull::docbook(odocstream
& os
, OutputParams
const & runparams
) const
1688 if (getType() == hullSimple
)
1689 name
= from_ascii("inlineequation");
1691 name
= from_ascii("informalequation");
1693 docstring bname
= name
;
1694 if (!label(0).empty())
1695 bname
+= " id='" + sgml::cleanID(buffer(), runparams
, label(0)) + "'";
1697 ++ms
.tab(); ms
.cr(); ms
.os() << '<' << bname
<< '>';
1699 odocstringstream ls
;
1700 if (runparams
.flavor
== OutputParams::XML
) {
1701 ms
<< MTag("alt role='tex' ");
1702 // Workaround for db2latex: db2latex always includes equations with
1703 // \ensuremath{} or \begin{display}\end{display}
1704 // so we strip LyX' math environment
1705 WriteStream
wi(ls
, false, false, WriteStream::wsDefault
, runparams
.encoding
);
1706 InsetMathGrid::write(wi
);
1707 ms
<< from_utf8(subst(subst(to_utf8(ls
.str()), "&", "&"), "<", "<"));
1712 InsetMathGrid::mathmlize(ms
);
1715 ms
<< MTag("alt role='tex'");
1716 res
= latex(ls
, runparams
);
1717 ms
<< from_utf8(subst(subst(to_utf8(ls
.str()), "&", "&"), "<", "<"));
1721 ms
<< from_ascii("<graphic fileref=\"eqn/");
1722 if (!label(0).empty())
1723 ms
<< sgml::cleanID(buffer(), runparams
, label(0));
1725 ms
<< sgml::uniqueID(from_ascii("anon"));
1727 if (runparams
.flavor
== OutputParams::XML
)
1728 ms
<< from_ascii("\"/>");
1730 ms
<< from_ascii("\">");
1732 ms
.cr(); --ms
.tab(); ms
.os() << "</" << name
<< '>';
1734 return ms
.line() + res
;
1738 void InsetMathHull::tocString(odocstream
& os
) const
1740 plaintext(os
, OutputParams(0));
1744 docstring
InsetMathHull::contextMenu(BufferView
const &, int, int) const
1746 return from_ascii("context-math");