3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
7 * \author Stefan Schimanski
9 * Full author contact details are available in file CREDITS.
16 #include "InsetMathBrace.h"
17 #include "InsetMathFont.h"
18 #include "InsetMathScript.h"
19 #include "MacroTable.h"
20 #include "MathMacro.h"
21 #include "MathStream.h"
22 #include "MathSupport.h"
23 #include "MetricsInfo.h"
24 #include "ReplaceData.h"
27 #include "BufferView.h"
28 #include "CoordCache.h"
31 #include "mathed/InsetMathUnknown.h"
33 #include "support/debug.h"
34 #include "support/docstream.h"
36 #include "frontends/FontMetrics.h"
37 #include "frontends/Painter.h"
39 #include "support/lassert.h"
40 #include <boost/next_prior.hpp>
49 MathData::MathData(Buffer
* buf
, const_iterator from
, const_iterator to
)
50 : base_type(from
, to
), buffer_(buf
)
54 MathAtom
& MathData::operator[](pos_type pos
)
56 LASSERT(pos
< size(), /**/);
57 return base_type::operator[](pos
);
61 MathAtom
const & MathData::operator[](pos_type pos
) const
63 LASSERT(pos
< size(), /**/);
64 return base_type::operator[](pos
);
68 void MathData::insert(size_type pos
, MathAtom
const & t
)
70 base_type::insert(begin() + pos
, t
);
74 void MathData::insert(size_type pos
, MathData
const & ar
)
76 LASSERT(pos
<= size(), /**/);
77 base_type::insert(begin() + pos
, ar
.begin(), ar
.end());
81 void MathData::append(MathData
const & ar
)
87 void MathData::erase(size_type pos
)
94 void MathData::erase(iterator pos1
, iterator pos2
)
96 base_type::erase(pos1
, pos2
);
100 void MathData::erase(iterator pos
)
102 base_type::erase(pos
);
106 void MathData::erase(size_type pos1
, size_type pos2
)
108 base_type::erase(begin() + pos1
, begin() + pos2
);
112 void MathData::dump2() const
116 for (const_iterator it
= begin(); it
!= end(); ++it
)
118 lyxerr
<< to_utf8(os
.str());
122 void MathData::dump() const
126 for (const_iterator it
= begin(); it
!= end(); ++it
)
127 ns
<< '<' << *it
<< '>';
128 lyxerr
<< to_utf8(os
.str());
132 void MathData::validate(LaTeXFeatures
& features
) const
134 for (const_iterator it
= begin(); it
!= end(); ++it
)
135 (*it
)->validate(features
);
139 bool MathData::match(MathData
const & ar
) const
141 return size() == ar
.size() && matchpart(ar
, 0);
145 bool MathData::matchpart(MathData
const & ar
, pos_type pos
) const
147 if (size() < ar
.size() + pos
)
149 const_iterator it
= begin() + pos
;
150 for (const_iterator jt
= ar
.begin(); jt
!= ar
.end(); ++jt
, ++it
)
151 if (asString(*it
) != asString(*jt
))
157 void MathData::replace(ReplaceData
& rep
)
159 for (size_type i
= 0; i
< size(); ++i
) {
160 if (find1(rep
.from
, i
)) {
162 lyxerr
<< "match found!" << endl
;
163 erase(i
, i
+ rep
.from
.size());
168 // FIXME: temporarily disabled
169 // for (const_iterator it = begin(); it != end(); ++it)
170 // it->nucleus()->replace(rep);
174 bool MathData::find1(MathData
const & ar
, size_type pos
) const
176 lyxerr
<< "finding '" << ar
<< "' in '" << *this << "'" << endl
;
177 for (size_type i
= 0, n
= ar
.size(); i
< n
; ++i
)
178 if (asString(operator[](pos
+ i
)) != asString(ar
[i
]))
184 MathData::size_type
MathData::find(MathData
const & ar
) const
186 for (int i
= 0, last
= size() - ar
.size(); i
< last
; ++i
)
193 MathData::size_type
MathData::find_last(MathData
const & ar
) const
195 for (int i
= size() - ar
.size(); i
>= 0; --i
)
202 bool MathData::contains(MathData
const & ar
) const
204 if (find(ar
) != size())
206 for (const_iterator it
= begin(); it
!= end(); ++it
)
207 if ((*it
)->contains(ar
))
213 void MathData::touch() const
220 bool isInside(DocIterator
const & it
, MathData
const & ar
,
221 pos_type p1
, pos_type p2
)
223 for (size_t i
= 0; i
!= it
.depth(); ++i
) {
224 CursorSlice
const & sl
= it
[i
];
225 if (sl
.inset().inMathed() && &sl
.cell() == &ar
)
226 return p1
<= sl
.pos() && sl
.pos() < p2
;
235 void MathData::metrics(MetricsInfo
& mi
, Dimension
& dim
) const
237 frontend::FontMetrics
const & fm
= theFontMetrics(mi
.base
.font
);
238 dim
= fm
.dimension('I');
239 int xascent
= fm
.dimension('x').ascent();
240 if (xascent
>= dim
.asc
)
241 xascent
= (2 * dim
.asc
) / 3;
243 mindes_
= (3 * xascent
) / 4;
244 slevel_
= (4 * xascent
) / 5;
245 sshift_
= xascent
/ 4;
249 // Cache the dimension.
250 mi
.base
.bv
->coordCache().arrays().add(this, dim
);
254 Cursor
& cur
= mi
.base
.bv
->cursor();
255 const_cast<MathData
*>(this)->updateMacros(&cur
, mi
.macrocontext
);
257 DocIterator
const & inlineCompletionPos
= mi
.base
.bv
->inlineCompletionPos();
258 MathData
const * inlineCompletionData
= 0;
259 if (inlineCompletionPos
.inMathed())
260 inlineCompletionData
= &inlineCompletionPos
.cell();
265 CoordCacheBase
<Inset
> & coords
= mi
.base
.bv
->coordCache().insets();
266 for (pos_type i
= 0, n
= size(); i
!= n
; ++i
) {
267 MathAtom
const & at
= operator[](i
);
269 coords
.add(at
.nucleus(), d
);
272 kerning_
= at
->kerning(mi
.base
.bv
);
274 // HACK to draw completion suggestion inline
275 if (inlineCompletionData
!= this
276 || size_t(inlineCompletionPos
.pos()) != i
+ 1)
279 docstring
const & completion
= mi
.base
.bv
->inlineCompletion();
280 if (completion
.length() == 0)
283 dim
.wid
+= mathed_string_width(mi
.base
.font
, completion
);
285 // Cache the dimension.
286 mi
.base
.bv
->coordCache().arrays().add(this, dim
);
290 void MathData::draw(PainterInfo
& pi
, int x
, int y
) const
292 //lyxerr << "MathData::draw: x: " << x << " y: " << y << endl;
293 BufferView
& bv
= *pi
.base
.bv
;
296 Dimension
const & dim
= bv
.coordCache().getArrays().dim(this);
299 pi
.pain
.rectangle(x
, y
- dim
.ascent(), dim
.width(), dim
.height(), Color_mathline
);
303 // don't draw outside the workarea
304 if (y
+ dim
.descent() <= 0
305 || y
- dim
.ascent() >= bv
.workHeight()
306 || x
+ dim
.width() <= 0
307 || x
>= bv
. workWidth())
310 DocIterator
const & inlineCompletionPos
= bv
.inlineCompletionPos();
311 MathData
const * inlineCompletionData
= 0;
312 if (inlineCompletionPos
.inMathed())
313 inlineCompletionData
= &inlineCompletionPos
.cell();
315 CoordCacheBase
<Inset
> & coords
= pi
.base
.bv
->coordCache().insets();
316 for (size_t i
= 0, n
= size(); i
!= n
; ++i
) {
317 MathAtom
const & at
= operator[](i
);
318 coords
.add(at
.nucleus(), x
, y
);
319 at
->drawSelection(pi
, x
, y
);
321 x
+= coords
.dim(at
.nucleus()).wid
;
323 // Is the inline completion here?
324 if (inlineCompletionData
!= this
325 || size_t(inlineCompletionPos
.pos()) != i
+ 1)
327 docstring
const & completion
= bv
.inlineCompletion();
328 if (completion
.length() == 0)
330 FontInfo f
= pi
.base
.font
;
332 // draw the unique and the non-unique completion part
333 // Note: this is not time-critical as it is
334 // only done once per screen.
335 size_t uniqueTo
= bv
.inlineCompletionUniqueChars();
336 docstring s1
= completion
.substr(0, uniqueTo
);
337 docstring s2
= completion
.substr(uniqueTo
);
340 f
.setColor(Color_inlinecompletion
);
341 pi
.pain
.text(x
, y
, s1
, f
);
342 x
+= mathed_string_width(f
, s1
);
346 f
.setColor(Color_nonunique_inlinecompletion
);
347 pi
.pain
.text(x
, y
, s2
, f
);
348 x
+= mathed_string_width(f
, s2
);
354 void MathData::metricsT(TextMetricsInfo
const & mi
, Dimension
& dim
) const
358 for (const_iterator it
= begin(); it
!= end(); ++it
) {
359 (*it
)->metricsT(mi
, d
);
365 void MathData::drawT(TextPainter
& pain
, int x
, int y
) const
367 //lyxerr << "x: " << x << " y: " << y << ' ' << pain.workAreaHeight() << endl;
369 // FIXME: Abdel 16/10/2006
370 // This drawT() method is never used, this is dead code.
372 for (const_iterator it
= begin(), et
= end(); it
!= et
; ++it
) {
373 (*it
)->drawT(pain
, x
, y
);
374 //x += (*it)->width_;
380 void MathData::updateMacros(Cursor
* cur
, MacroContext
const & mc
)
382 // go over the array and look for macros
383 for (size_t i
= 0; i
< size(); ++i
) {
384 MathMacro
* macroInset
= operator[](i
).nucleus()->asMacro();
385 if (!macroInset
|| macroInset
->name_
[0] == '^'
386 || macroInset
->name_
[0] == '_')
390 macroInset
->updateMacro(mc
);
391 size_t macroNumArgs
= 0;
392 size_t macroOptionals
= 0;
393 MacroData
const * macro
= macroInset
->macro();
395 macroNumArgs
= macro
->numargs();
396 macroOptionals
= macro
->optionals();
399 // store old and compute new display mode
400 MathMacro::DisplayMode newDisplayMode
;
401 MathMacro::DisplayMode oldDisplayMode
= macroInset
->displayMode();
402 newDisplayMode
= macroInset
->computeDisplayMode();
404 // arity changed or other reason to detach?
405 if (oldDisplayMode
== MathMacro::DISPLAY_NORMAL
406 && (macroInset
->arity() != macroNumArgs
407 || macroInset
->optionals() != macroOptionals
408 || newDisplayMode
== MathMacro::DISPLAY_UNFOLDED
)) {
410 detachMacroParameters(cur
, i
);
413 // the macro could have been copied while resizing this
414 macroInset
= operator[](i
).nucleus()->asMacro();
417 if (newDisplayMode
!= MathMacro::DISPLAY_UNFOLDED
418 && oldDisplayMode
== MathMacro::DISPLAY_UNFOLDED
) {
419 // put cursor in front of macro
421 int macroSlice
= cur
->find(macroInset
);
422 if (macroSlice
!= -1)
423 cur
->cutOff(macroSlice
- 1);
427 // update the display mode
428 size_t appetite
= macroInset
->appetite();
429 macroInset
->setDisplayMode(newDisplayMode
);
432 if (newDisplayMode
== MathMacro::DISPLAY_NORMAL
433 && (macroInset
->arity() != macroNumArgs
434 || macroInset
->optionals() != macroOptionals
)) {
435 // is it a virgin macro which was never attached to parameters?
436 bool fromInitToNormalMode
437 = (oldDisplayMode
== MathMacro::DISPLAY_INIT
438 || oldDisplayMode
== MathMacro::DISPLAY_INTERACTIVE_INIT
)
439 && newDisplayMode
== MathMacro::DISPLAY_NORMAL
;
441 // if the macro was entered interactively (i.e. not by paste or during
442 // loading), it should not be greedy, but the cursor should
443 // automatically jump into the macro when behind
444 bool interactive
= (oldDisplayMode
== MathMacro::DISPLAY_INTERACTIVE_INIT
);
447 attachMacroParameters(cur
, i
, macroNumArgs
, macroOptionals
,
448 fromInitToNormalMode
, interactive
, appetite
);
451 // FIXME: proper anchor handling, this removes the selection
452 cur
->updateInsets(&cur
->bottom().inset());
453 cur
->clearSelection();
457 // Give macro the chance to adapt to new situation.
458 // The macroInset could be invalid now because it was put into a script
459 // inset and therefore "deep" copied. So get it again from the MathData.
460 InsetMath
* inset
= operator[](i
).nucleus();
461 if (inset
->asScriptInset())
462 inset
= inset
->asScriptInset()->nuc()[0].nucleus();
463 LASSERT(inset
->asMacro(), /**/);
464 inset
->asMacro()->updateRepresentation();
469 void MathData::detachMacroParameters(Cursor
* cur
, const size_type macroPos
)
471 MathMacro
* macroInset
= operator[](macroPos
).nucleus()->asMacro();
472 Buffer
* buf
= cur
->buffer();
474 // detach all arguments
475 vector
<MathData
> detachedArgs
;
476 if (macroPos
+ 1 == size())
477 // strip arguments if we are at the MathData end
478 macroInset
->detachArguments(detachedArgs
, true);
480 macroInset
->detachArguments(detachedArgs
, false);
483 int curMacroSlice
= -1;
485 curMacroSlice
= cur
->find(macroInset
);
486 idx_type curMacroIdx
= -1;
487 pos_type curMacroPos
= -1;
488 vector
<CursorSlice
> argSlices
;
489 if (curMacroSlice
!= -1) {
490 curMacroPos
= (*cur
)[curMacroSlice
].pos();
491 curMacroIdx
= (*cur
)[curMacroSlice
].idx();
492 cur
->cutOff(curMacroSlice
, argSlices
);
496 // only [] after the last non-empty argument can be dropped later
497 size_t lastNonEmptyOptional
= 0;
498 for (size_t l
= 0; l
< detachedArgs
.size() && l
< macroInset
->optionals(); ++l
) {
499 if (!detachedArgs
[l
].empty())
500 lastNonEmptyOptional
= l
;
503 // optional arguments to be put back?
504 pos_type p
= macroPos
+ 1;
506 for (; j
< detachedArgs
.size() && j
< macroInset
->optionals(); ++j
) {
507 // another non-empty parameter follows?
508 bool canDropEmptyOptional
= j
>= lastNonEmptyOptional
;
510 // then we can drop empty optional parameters
511 if (detachedArgs
[j
].empty() && canDropEmptyOptional
) {
512 if (curMacroIdx
== j
)
513 (*cur
)[curMacroSlice
- 1].pos() = macroPos
+ 1;
517 // Otherwise we don't drop an empty optional, put it back normally
519 asArray(from_ascii("[]"), optarg
);
520 MathData
& arg
= detachedArgs
[j
];
522 // look for "]", i.e. put a brace around?
523 InsetMathBrace
* brace
= 0;
524 for (size_t q
= 0; q
< arg
.size(); ++q
) {
525 if (arg
[q
]->getChar() == ']') {
527 brace
= new InsetMathBrace(buf
);
532 // put arg between []
534 brace
->cell(0) = arg
;
535 optarg
.insert(1, MathAtom(brace
));
537 optarg
.insert(1, arg
);
539 // insert it into the array
544 if (curMacroSlice
== -1)
547 // cursor in optional argument of macro?
548 if (curMacroIdx
== j
) {
550 cur
->append(0, curMacroPos
);
551 (*cur
)[curMacroSlice
- 1].pos() = macroPos
+ 2;
553 (*cur
)[curMacroSlice
- 1].pos() = macroPos
+ 2 + curMacroPos
;
554 cur
->append(argSlices
);
555 } else if ((*cur
)[curMacroSlice
- 1].pos() >= int(p
))
556 // cursor right of macro
557 (*cur
)[curMacroSlice
- 1].pos() += optarg
.size();
560 // put them back into the MathData
561 for (; j
< detachedArgs
.size(); ++j
, ++p
) {
562 MathData
const & arg
= detachedArgs
[j
];
564 && !arg
[0]->asScriptInset()
565 && !(arg
[0]->asMacro() && arg
[0]->asMacro()->arity() > 0))
568 insert(p
, MathAtom(new InsetMathBrace(arg
)));
571 if (curMacroSlice
== -1)
574 // cursor in j-th argument of macro?
575 if (curMacroIdx
== j
) {
576 if (operator[](p
).nucleus()->asBraceInset()) {
577 (*cur
)[curMacroSlice
- 1].pos() = p
;
578 cur
->append(0, curMacroPos
);
579 cur
->append(argSlices
);
581 (*cur
)[curMacroSlice
- 1].pos() = p
; // + macroPos;
582 cur
->append(argSlices
);
584 } else if ((*cur
)[curMacroSlice
- 1].pos() >= int(p
))
585 ++(*cur
)[curMacroSlice
- 1].pos();
589 // FIXME: proper anchor handling, this removes the selection
590 cur
->clearSelection();
591 cur
->updateInsets(&cur
->bottom().inset());
596 void MathData::attachMacroParameters(Cursor
* cur
,
597 const size_type macroPos
, const size_type macroNumArgs
,
598 const int macroOptionals
, const bool fromInitToNormalMode
,
599 const bool interactiveInit
, const size_t appetite
)
601 MathMacro
* macroInset
= operator[](macroPos
).nucleus()->asMacro();
603 // start at atom behind the macro again, maybe with some new arguments
604 // from the detach phase above, to add them back into the macro inset
605 size_t p
= macroPos
+ 1;
606 vector
<MathData
> detachedArgs
;
607 MathAtom scriptToPutAround
;
609 // find cursor slice again of this MathData
612 thisSlice
= cur
->find(*this);
615 thisPos
= (*cur
)[thisSlice
].pos();
617 // find arguments behind the macro
618 if (!interactiveInit
) {
619 collectOptionalParameters(cur
, macroOptionals
, detachedArgs
, p
,
620 scriptToPutAround
, macroPos
, thisPos
, thisSlice
);
622 collectParameters(cur
, macroNumArgs
, detachedArgs
, p
,
623 scriptToPutAround
, macroPos
, thisPos
, thisSlice
, appetite
);
625 // attach arguments back to macro inset
626 macroInset
->attachArguments(detachedArgs
, macroNumArgs
, macroOptionals
);
628 // found tail script? E.g. \foo{a}b^x
629 if (scriptToPutAround
.nucleus()) {
630 // put macro into a script inset
631 scriptToPutAround
.nucleus()->asScriptInset()->nuc()[0]
632 = operator[](macroPos
);
633 operator[](macroPos
) = scriptToPutAround
;
635 // go into the script inset nucleus
636 if (cur
&& thisPos
== int(macroPos
))
639 // get pointer to "deep" copied macro inset
640 InsetMathScript
* scriptInset
641 = operator[](macroPos
).nucleus()->asScriptInset();
642 macroInset
= scriptInset
->nuc()[0].nucleus()->asMacro();
645 // remove them from the MathData
646 erase(begin() + macroPos
+ 1, begin() + p
);
648 // cursor outside this MathData?
652 // fix cursor if right of p
653 if (thisPos
>= int(p
))
654 (*cur
)[thisSlice
].pos() -= p
- (macroPos
+ 1);
656 // was the macro inset just inserted interactively and was now folded
657 // and the cursor is just behind?
658 if ((*cur
)[thisSlice
].pos() == int(macroPos
+ 1)
660 && fromInitToNormalMode
661 && macroInset
->arity() > 0
662 && thisSlice
+ 1 == int(cur
->depth())) {
663 // then enter it if the cursor was just behind
664 (*cur
)[thisSlice
].pos() = macroPos
;
665 cur
->push_back(CursorSlice(*macroInset
));
666 macroInset
->idxFirst(*cur
);
671 void MathData::collectOptionalParameters(Cursor
* cur
,
672 const size_type numOptionalParams
, vector
<MathData
> & params
,
673 size_t & pos
, MathAtom
& scriptToPutAround
,
674 const pos_type macroPos
, const int thisPos
, const int thisSlice
)
676 Buffer
* buf
= cur
? cur
->buffer() : 0;
677 // insert optional arguments?
678 while (params
.size() < numOptionalParams
680 && !scriptToPutAround
.nucleus()) {
681 // is a [] block following which could be an optional parameter?
682 if (operator[](pos
)->getChar() != '[')
685 // found possible optional argument, look for "]"
686 size_t right
= pos
+ 1;
687 for (; right
< size(); ++right
) {
688 MathAtom
& cell
= operator[](right
);
690 if (cell
->getChar() == ']')
694 // maybe "]" with a script around?
695 InsetMathScript
* script
= cell
.nucleus()->asScriptInset();
698 if (script
->nuc().size() != 1)
700 if (script
->nuc()[0]->getChar() == ']') {
701 // script will be put around the macro later
702 scriptToPutAround
= cell
;
708 if (right
>= size()) {
709 // no ] found, so it's not an optional argument
713 // add everything between [ and ] as optional argument
714 MathData
optarg(buf
, begin() + pos
+ 1, begin() + right
);
718 if (optarg
.size() == 1 && optarg
[0]->asBraceInset()) {
720 params
.push_back(optarg
[0]->asBraceInset()->cell(0));
722 params
.push_back(optarg
);
724 // place cursor in optional argument of macro
726 && thisPos
>= int(pos
) && thisPos
<= int(right
)) {
727 int paramPos
= max(0, thisPos
- int(pos
) - 1);
728 vector
<CursorSlice
> x
;
729 cur
->cutOff(thisSlice
, x
);
730 (*cur
)[thisSlice
].pos() = macroPos
;
732 paramPos
= x
[0].pos();
735 cur
->append(0, paramPos
);
741 // fill up empty optional parameters
742 while (params
.size() < numOptionalParams
)
743 params
.push_back(MathData());
747 void MathData::collectParameters(Cursor
* cur
,
748 const size_type numParams
, vector
<MathData
> & params
,
749 size_t & pos
, MathAtom
& scriptToPutAround
,
750 const pos_type macroPos
, const int thisPos
, const int thisSlice
,
751 const size_t appetite
)
753 size_t startSize
= params
.size();
755 // insert normal arguments
756 while (params
.size() < numParams
757 && params
.size() - startSize
< appetite
759 && !scriptToPutAround
.nucleus()) {
760 MathAtom
& cell
= operator[](pos
);
763 vector
<CursorSlice
> argSlices
;
765 if (thisSlice
!= -1 && thisPos
== int(pos
))
766 cur
->cutOff(thisSlice
, argSlices
);
768 // which kind of parameter is it? In {}? With index x^n?
769 InsetMathBrace
const * brace
= cell
->asBraceInset();
771 // found brace, convert into argument
772 params
.push_back(brace
->cell(0));
774 // cursor inside of the brace or just in front of?
775 if (thisPos
== int(pos
) && !argSlices
.empty()) {
776 argPos
= argSlices
[0].pos();
777 argSlices
.erase(argSlices
.begin());
779 } else if (cell
->asScriptInset() && params
.size() + 1 == numParams
) {
780 // last inset with scripts without braces
781 // -> they belong to the macro, not the argument
782 InsetMathScript
* script
= cell
.nucleus()->asScriptInset();
783 if (script
->nuc().size() == 1 && script
->nuc()[0]->asBraceInset())
784 // nucleus in brace? Unpack!
785 params
.push_back(script
->nuc()[0]->asBraceInset()->cell(0));
787 params
.push_back(script
->nuc());
789 // script will be put around below
790 scriptToPutAround
= cell
;
792 // this should only happen after loading, so make cursor handling simple
793 if (thisPos
>= int(macroPos
) && thisPos
<= int(macroPos
+ numParams
)) {
799 // the simplest case: plain inset
801 array
.insert(0, cell
);
802 params
.push_back(array
);
805 // put cursor in argument again
806 if (thisSlice
!= - 1 && thisPos
== int(pos
)) {
807 cur
->append(params
.size() - 1, argPos
);
808 cur
->append(argSlices
);
809 (*cur
)[thisSlice
].pos() = macroPos
;
817 int MathData::pos2x(BufferView
const * bv
, size_type pos
) const
819 return pos2x(bv
, pos
, 0);
823 int MathData::pos2x(BufferView
const * bv
, size_type pos
, int glue
) const
826 size_type target
= min(pos
, size());
827 CoordCacheBase
<Inset
> const & coords
= bv
->coordCache().getInsets();
828 for (size_type i
= 0; i
< target
; ++i
) {
829 const_iterator it
= begin() + i
;
830 if ((*it
)->getChar() == ' ')
832 //lyxerr << "char: " << (*it)->getChar()
833 // << "width: " << (*it)->width() << endl;
834 x
+= coords
.dim((*it
).nucleus()).wid
;
840 MathData::size_type
MathData::x2pos(BufferView
const * bv
, int targetx
) const
842 return x2pos(bv
, targetx
, 0);
846 MathData::size_type
MathData::x2pos(BufferView
const * bv
, int targetx
, int glue
) const
848 const_iterator it
= begin();
851 CoordCacheBase
<Inset
> const & coords
= bv
->coordCache().getInsets();
852 // find first position after targetx
853 for (; currx
< targetx
&& it
< end(); ++it
) {
855 if ((*it
)->getChar() == ' ')
857 currx
+= coords
.dim((*it
).nucleus()).wid
;
861 * If we are not at the beginning of the array, go to the left
862 * of the inset if one of the following two condition holds:
863 * - the current inset is editable (so that the cursor tip is
864 * deeper than us): in this case, we want all intermediate
865 * cursor slices to be before insets;
866 * - the mouse is closer to the left side of the inset than to
868 * See bug 1918 for details.
870 if (it
!= begin() && currx
>= targetx
871 && ((*boost::prior(it
))->asNestInset()
872 || abs(lastx
- targetx
) < abs(currx
- targetx
))) {
880 int MathData::dist(BufferView
const & bv
, int x
, int y
) const
882 return bv
.coordCache().getArrays().squareDistance(this, x
, y
);
886 void MathData::setXY(BufferView
& bv
, int x
, int y
) const
888 //lyxerr << "setting position cache for MathData " << this << endl;
889 bv
.coordCache().arrays().add(this, x
, y
);
893 Dimension
const & MathData::dimension(BufferView
const & bv
) const
895 return bv
.coordCache().getArrays().dim(this);
899 int MathData::xm(BufferView
const & bv
) const
901 Geometry
const & g
= bv
.coordCache().getArrays().geometry(this);
903 return g
.pos
.x_
+ g
.dim
.wid
/ 2;
907 int MathData::ym(BufferView
const & bv
) const
909 Geometry
const & g
= bv
.coordCache().getArrays().geometry(this);
911 return g
.pos
.y_
+ (g
.dim
.des
- g
.dim
.asc
) / 2;
915 int MathData::xo(BufferView
const & bv
) const
917 return bv
.coordCache().getArrays().x(this);
921 int MathData::yo(BufferView
const & bv
) const
923 return bv
.coordCache().getArrays().y(this);
927 ostream
& operator<<(ostream
& os
, MathData
const & ar
)
929 odocstringstream oss
;
930 NormalStream
ns(oss
);
932 return os
<< to_utf8(oss
.str());
936 odocstream
& operator<<(odocstream
& os
, MathData
const & ar
)