2 /* This file is part of
3 * ======================================================
5 * LyX, The Document Processor
7 * Copyright 1998 The LyX Team.
9 * ======================================================
20 #pragma implementation
23 #include "insettext.h"
28 #include "commandtags.h"
31 #include "BufferView.h"
32 #include "support/textutils.h"
34 #include "insetlatexaccent.h"
35 #include "insetquotes.h"
36 #include "mathed/formulamacro.h"
38 #include "insetinfo.h"
39 #include "insetinclude.h"
41 #include "insetcommand.h"
42 #include "insetindex.h"
43 #include "insetlabel.h"
45 //#include "insettabular.h"
47 #include "insetspecialchar.h"
48 #include "LaTeXFeatures.h"
50 #include "lyx_gui_misc.h"
51 #include "support/LAssert.h"
53 extern unsigned char getCurrentTextClass(Buffer *);
55 InsetText::InsetText(Buffer * buf)
57 par = new LyXParagraph();
58 the_locking_inset = 0;
60 cursor_visible = false;
61 maxWidth = old_x = -1;
62 actpos = selection_start = selection_end = 0;
69 InsetText::InsetText(InsetText const & ins, Buffer * buf)
71 par = new LyXParagraph(ins.par);
72 the_locking_inset = 0;
74 cursor_visible = false;
75 maxWidth = old_x = -1;
76 actpos = selection_start = selection_end = 0;
83 InsetText::~InsetText()
89 Inset * InsetText::Clone() const
91 InsetText * t = new InsetText(*this, buffer);
96 void InsetText::Write(ostream & os) const
99 WriteParagraphData(os);
103 void InsetText::WriteParagraphData(ostream & os) const
105 LyXFont font1 = LyXFont(LyXFont::ALL_INHERIT);
110 for (int i = 0; i < par->Last(); ++i) {
111 // Write font changes
112 font2 = par->GetFontSettings(i);
113 if (font2 != font1) {
114 font2.lyxWriteChanges(font1, os);
119 // A newline before tags
121 (c == LyXParagraph::META_INSET ||
122 c == LyXParagraph::META_NEWLINE ||
129 case LyXParagraph::META_INSET: {
130 Inset * inset = par->GetInset(i);
132 os << "\n\\begin_inset ";
134 os << "\n\\end_inset \n\n";
139 case LyXParagraph::META_NEWLINE:
144 os << "\\backslash\n";
148 if (column > 65 && c==' ') {
152 // this check is to amend a bug. LyX sometimes
153 // inserts '\0' this could cause problems.
157 lyxerr << "ERROR (InsetText::writeFile):"
158 " '\\0' char in structure.\n";
163 // A newline if the last c was not a tag.
165 (c != LyXParagraph::META_INSET &&
166 c != LyXParagraph::META_NEWLINE &&
174 void InsetText::Read(LyXLex & lex)
176 string token, tmptok;
177 LyXFont font = LyXFont(LyXFont::ALL_INHERIT);
181 par = new LyXParagraph;
185 token = lex.GetString();
188 else if (token[0] != '\\') {
189 int n = token.length();
190 for (int i = 0; i < n; ++i) {
191 par->InsertChar(pos, token[i]);
192 par->SetFont(pos, font);
195 } else if (token == "\\newline") {
196 par->InsertChar(pos, LyXParagraph::META_NEWLINE);
197 par->SetFont(pos, font);
199 } else if (token == "\\family") {
201 font.setLyXFamily(lex.GetString());
202 } else if (token == "\\series") {
204 font.setLyXSeries(lex.GetString());
205 } else if (token == "\\shape") {
207 font.setLyXShape(lex.GetString());
208 } else if (token == "\\size") {
210 font.setLyXSize(lex.GetString());
211 } else if (token == "\\latex") {
213 string tok = lex.GetString();
214 // This is dirty, but gone with LyX3. (Asger)
215 if (tok == "no_latex")
216 font.setLatex(LyXFont::OFF);
217 else if (tok == "latex")
218 font.setLatex(LyXFont::ON);
219 else if (tok == "default")
220 font.setLatex(LyXFont::INHERIT);
222 lex.printError("Unknown LaTeX font flag "
224 } else if (token == "\\direction") {
226 string tok = lex.GetString();
228 font.setDirection(LyXFont::LTR_DIR);
229 else if (tok == "rtl")
230 font.setDirection(LyXFont::RTL_DIR);
231 else if (tok == "default")
232 font.setDirection(LyXFont::INHERIT_DIR);
234 lex.printError("Unknown font flag "
236 } else if (token == "\\emph") {
238 font.setEmph(font.setLyXMisc(lex.GetString()));
239 } else if (token == "\\bar") {
241 string tok = lex.GetString();
242 // This is dirty, but gone with LyX3. (Asger)
244 font.setUnderbar(LyXFont::ON);
245 else if (tok == "no")
246 font.setUnderbar(LyXFont::OFF);
247 else if (tok == "default")
248 font.setUnderbar(LyXFont::INHERIT);
250 lex.printError("Unknown bar font flag "
252 } else if (token == "\\noun") {
254 font.setNoun(font.setLyXMisc(lex.GetString()));
255 } else if (token == "\\color") {
257 font.setLyXColor(lex.GetString());
258 } else if (token == "\\begin_inset") {
261 tmptok = lex.GetString();
262 // Test the different insets.
263 if (tmptok == "Quotes") {
264 inset = new InsetQuotes(string());
266 } else if (tmptok == "LaTeXAccent" || tmptok == "\\i") {
267 inset = new InsetLatexAccent;
269 } else if (tmptok == "FormulaMacro") {
270 inset = new InsetFormulaMacro;
272 } else if (tmptok == "Formula") {
273 inset = new InsetFormula;
275 } else if (tmptok == "Figure") {
276 inset = new InsetFig(100,100, buffer);
279 } else if (tmptok == "Tabular") {
280 inset = new InsetTabular(buffer);
283 } else if (tmptok == "Text") {
284 inset = new InsetText(buffer);
286 } else if (tmptok == "ERT") {
287 inset = new InsetERT(buffer);
289 } else if (tmptok == "Info") {
290 inset = new InsetInfo;
292 } else if (tmptok == "Include") {
293 inset = new InsetInclude(string(), buffer);
295 } else if (tmptok == "LatexCommand") {
298 if (inscmd.getCmdName()=="cite") {
299 inset = new InsetCitation(inscmd.getContents(),
300 inscmd.getOptions());
301 } else if (inscmd.getCmdName()=="bibitem") {
302 lex.printError("Wrong place for bibitem");
303 inset = inscmd.Clone();
304 } else if (inscmd.getCmdName()=="BibTeX") {
305 inset = new InsetBibtex(inscmd.getContents(),
306 inscmd.getOptions(), buffer);
307 } else if (inscmd.getCmdName()=="index") {
308 inset = new InsetIndex(inscmd.getContents());
309 } else if (inscmd.getCmdName()=="include") {
310 inset = new InsetInclude(inscmd.getContents(), buffer);
311 } else if (inscmd.getCmdName()=="label") {
312 inset = new InsetLabel(inscmd.getCommand());
313 } else if (inscmd.getCmdName() == "ref" ||
314 inscmd.getCmdName() == "pageref") {
315 inset = new InsetRef(inscmd, buffer);
317 #if 0 // Is this compatibility code needed (Lgb)
319 // The following three are only for compatibility
320 if (inscmd.getCmdName()=="-") {
321 inset = new InsetSpecialChar(InsetSpecialChar::HYPHENATION);
322 } else if (inscmd.getCmdName()=="@.") {
323 inset = new InsetSpecialChar(InsetSpecialChar::END_OF_SENTENCE);
324 } else if (inscmd.getCmdName()=="ldots") {
325 inset = new InsetSpecialChar(InsetSpecialChar::LDOTS);
327 inset = inscmd.Clone();
331 par->InsertChar(pos, LyXParagraph::META_INSET);
332 par->InsertInset(pos, inset);
333 par->SetFont(pos, font);
336 lex.printError("Unknown inset `$$Token'. "
337 "Inserting as text.");
339 #ifndef NO_COMPABILITY
340 } else if (token == "\\hfill") {
341 // now obsolete, but we have a bak compability
342 // Inset * inset = new InsetSpecialChar(LyXParagraph::META_HFILL);
343 // par->InsertChar(pos, LyXParagraph::META_INSET);
344 // par->InsertInset(pos, inset);
345 par->InsertChar(pos, LyXParagraph::META_HFILL);
346 par->SetFont(pos, font);
348 } else if (token == "\\protected_separator") {
349 // now obsolete, but we have a back compability
350 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
351 //Inset * inset = new InsetSpecialChar(LyXParagraph::META_PROTECTED_SEPARATOR);
352 // par->InsertChar(pos, LyXParagraph::META_INSET);
353 // par->InsertInset(pos, inset);
354 par->SetFont(pos, font);
357 } else if (token == "\\bibitem") { // ale970302
359 par->bibkey = new InsetBibKey;
360 par->bibkey->Read(lex);
361 }else if (token == "\\backslash") {
362 par->InsertChar(pos, '\\');
363 par->SetFont(pos, font);
365 } else if (token == "\\end_inset") {
368 lex.printError("Unknown tabular token `$$Token'. Not handled!");
372 if (token != "\\end_inset") {
373 lex.printError("Missing \\end_inset at this point. "
380 int InsetText::ascent(Painter &pain, LyXFont const & font) const
383 computeTextRows(pain);
388 return font.maxAscent();
392 int InsetText::descent(Painter &pain, LyXFont const & font) const
395 computeTextRows(pain);
400 return font.maxDescent();
404 int InsetText::width(Painter &pain, LyXFont const &) const
407 computeTextRows(pain);
414 int InsetText::getMaxWidth(UpdatableInset * inset) const
416 if (!the_locking_inset) {
417 lyxerr << "Text: No locking inset in this inset.\n";
421 if (the_locking_inset==inset)
424 return the_locking_inset->getMaxWidth(inset);
428 void InsetText::draw(Painter & pain, LyXFont const & f,
429 int baseline, float & x) const
432 computeTextRows(pain);
433 // init_inset = false;
435 UpdatableInset::draw(pain, f, baseline, x);
437 bool do_reset_pos = (x != top_x) || (baseline != top_baseline);
439 top_baseline = baseline;
440 computeBaselines(baseline);
441 for(unsigned int r = 0; r < rows.size() - 1; ++r) {
442 drawRowSelection(pain, rows[r].pos, rows[r+1].pos, r,
443 rows[r].baseline, x);
444 drawRowText(pain, rows[r].pos, rows[r+1].pos, rows[r].baseline, x);
447 if (!the_locking_inset && do_reset_pos) {
448 // HideInsetCursor(bv);
450 // ShowInsetCursor(bv);
455 void InsetText::drawRowSelection(Painter & pain, int startpos, int endpos,
456 int row, int baseline, float x) const
462 if (selection_start > selection_end) {
463 s_start = selection_end;
464 s_end = selection_start;
466 s_start = selection_start;
467 s_end = selection_end;
469 if ((s_start > endpos) || (s_end < startpos))
473 int ssel_x = esel_x = int(x);
476 for(; p < endpos; ++p) {
479 if ((p >= s_start) && (p <= s_end))
481 char ch = par->GetChar(p);
482 font = GetFont(par,p);
483 if (IsFloatChar(ch)) {
485 } else if (ch == LyXParagraph::META_INSET) {
486 Inset const * tmpinset = par->GetInset(p);
487 x += tmpinset->width(pain, font);
489 x += pain.width(ch,font);
494 if ((p >= s_start) && (p <= s_end))
496 if (ssel_x < esel_x) {
497 pain.fillRectangle(int(ssel_x), baseline-rows[row].asc,
498 int(esel_x - ssel_x),
499 rows[row].asc + rows[row].desc,
505 void InsetText::drawRowText(Painter & pain, int startpos, int endpos,
506 int baseline, float x) const
508 Assert(endpos <= par->Last());
510 for(int p = startpos; p < endpos; ++p) {
511 char ch = par->GetChar(p);
512 LyXFont font = GetFont(par,p);
513 if (IsFloatChar(ch)) {
515 } else if (ch == LyXParagraph::META_INSET) {
516 Inset * tmpinset = par->GetInset(p);
518 tmpinset->draw(pain, font, baseline, x);
520 pain.text(int(x), baseline, ch, font);
521 x += pain.width(ch,font);
527 char const * InsetText::EditMessage() const
529 return _("Opened Text Inset");
533 void InsetText::Edit(BufferView * bv, int x, int y, unsigned int button)
535 UpdatableInset::Edit(bv, x, y, button);
538 the_locking_inset = 0;
539 inset_pos = inset_x = inset_y = 0;
542 selection_start = selection_end = actpos;
543 current_font = real_current_font = GetFont(par, actpos);
547 void InsetText::InsetUnlock(BufferView * bv)
549 if (the_locking_inset)
550 the_locking_inset->InsetUnlock(bv);
552 if (hasSelection()) {
553 selection_start = selection_end = actpos;
554 bv->updateInset(this, false);
556 the_locking_inset = 0;
557 no_selection = false;
561 bool InsetText::UnlockInsetInInset(BufferView * bv, Inset * inset, bool lr)
563 if (!the_locking_inset)
565 if (the_locking_inset == inset) {
566 the_locking_inset->InsetUnlock(bv);
567 the_locking_inset = 0;
569 moveRight(bv, false);
572 return the_locking_inset->UnlockInsetInInset(bv, inset,lr);
576 bool InsetText::UpdateInsetInInset(BufferView * bv, Inset * inset)
578 if (!the_locking_inset)
580 if (the_locking_inset != inset)
581 return the_locking_inset->UpdateInsetInInset(bv, inset);
583 inset->draw(bv->getPainter(), real_current_font, inset_y, x);
584 bv->updateInset(this, true);
589 void InsetText::InsetButtonRelease(BufferView * bv, int x, int y, int button)
591 if (the_locking_inset) {
592 the_locking_inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
595 no_selection = false;
599 void InsetText::InsetButtonPress(BufferView * bv, int x, int y, int button)
601 if (hasSelection()) {
602 selection_start = selection_end = actpos;
603 bv->updateInset(this, false);
605 no_selection = false;
606 if (the_locking_inset) {
607 setPos(bv, x,y,false);
610 if (par->GetChar(actpos)==LyXParagraph::META_INSET)
611 inset=(UpdatableInset*)par->GetInset(actpos);
612 if (the_locking_inset == inset) {
613 the_locking_inset->InsetButtonPress(bv,x-inset_x,y-inset_y,button);
616 // otherwise unlock the_locking_inset and lock the new inset
620 the_locking_inset->InsetUnlock(bv);
621 the_locking_inset = inset;
622 the_locking_inset->Edit(bv, x - inset_x, y - inset_y, button);
625 // otherwise only unlock the_locking_inset
626 the_locking_inset->InsetUnlock(bv);
629 the_locking_inset = 0;
631 selection_start = selection_end = actpos;
632 if (!the_locking_inset)
637 void InsetText::InsetMotionNotify(BufferView * bv, int x, int y, int button)
639 if (the_locking_inset) {
640 the_locking_inset->InsetMotionNotify(bv, x - inset_x,
645 int old = selection_end;
646 setPos(bv, x, y, false);
647 selection_end = actpos;
648 if (old != selection_end)
649 bv->updateInset(this, false);
651 no_selection = false;
655 void InsetText::InsetKeyPress(XKeyEvent * xke)
657 if (the_locking_inset) {
658 the_locking_inset->InsetKeyPress(xke);
664 UpdatableInset::RESULT InsetText::LocalDispatch(BufferView * bv,
665 int action, string const & arg)
667 no_selection = false;
668 if (UpdatableInset::LocalDispatch(bv, action, arg)) {
673 UpdatableInset::RESULT
676 if ((action < 0) && arg.empty())
679 if ((action != LFUN_DOWN) && (action != LFUN_UP) &&
680 (action != LFUN_DOWNSEL) && (action != LFUN_UPSEL))
682 if (the_locking_inset) {
683 result = the_locking_inset->LocalDispatch(bv, action, arg);
684 if (result == DISPATCHED) {
685 the_locking_inset->ToggleInsetCursor(bv);
686 bv->updateInset(this, false);
687 the_locking_inset->ToggleInsetCursor(bv);
689 } else if (result == FINISHED) {
690 if ((action == LFUN_RIGHT) || (action == -1)) {
691 actpos = inset_pos + 1;
694 the_locking_inset = 0;
702 par->InsertChar(actpos,arg[0]);
703 par->SetFont(actpos,real_current_font);
704 computeTextRows(bv->getPainter());
705 bv->updateInset(this, true);
707 selection_start = selection_end = actpos;
710 // --- Cursor Movements ---------------------------------------------
712 moveRight(bv, false);
713 selection_end = actpos;
714 bv->updateInset(this, false);
717 result= DISPATCH_RESULT(moveRight(bv));
718 if (hasSelection()) {
719 selection_start = selection_end = actpos;
720 bv->updateInset(this, false);
722 selection_start = selection_end = actpos;
727 selection_end = actpos;
728 bv->updateInset(this, false);
731 result= DISPATCH_RESULT(moveLeft(bv));
732 if (hasSelection()) {
733 selection_start = selection_end = actpos;
734 bv->updateInset(this, false);
736 selection_start = selection_end = actpos;
741 selection_end = actpos;
742 bv->updateInset(this, false);
745 result= DISPATCH_RESULT(moveDown(bv));
746 if (hasSelection()) {
747 selection_start = selection_end = actpos;
748 bv->updateInset(this, false);
750 selection_start = selection_end = actpos;
755 selection_end = actpos;
756 bv->updateInset(this, false);
759 result= DISPATCH_RESULT(moveUp(bv));
760 if (hasSelection()) {
761 selection_start = selection_end = actpos;
762 bv->updateInset(this, false);
764 selection_start = selection_end = actpos;
768 if (!actpos || par->IsNewline(actpos-1)) {
769 if (hasSelection()) {
770 selection_start = selection_end = actpos;
771 bv->updateInset(this, false);
777 if (Delete()) { // we need update
778 selection_start = selection_end = actpos;
779 computeTextRows(bv->getPainter());
780 bv->updateInset(this, true);
781 } else if (hasSelection()) {
782 selection_start = selection_end = actpos;
783 bv->updateInset(this, false);
787 for(; actpos > rows[actrow].pos; --actpos)
788 cx -= SingleWidth(bv->getPainter(), par, actpos);
789 cx -= SingleWidth(bv->getPainter(), par, actpos);
790 if (hasSelection()) {
791 selection_start = selection_end = actpos;
792 bv->updateInset(this, false);
794 selection_start = selection_end = actpos;
798 for(; actpos < rows[actrow + 1].pos; ++actpos)
799 cx += SingleWidth(bv->getPainter(), par, actpos);
800 if (hasSelection()) {
801 selection_start = selection_end = actpos;
802 bv->updateInset(this, false);
804 selection_start = selection_end = actpos;
807 case LFUN_MATH_MODE: // Open or create a math inset
808 InsertInset(bv, new InsetFormula);
809 if (hasSelection()) {
810 selection_start = selection_end = actpos;
811 bv->updateInset(this, false);
813 selection_start = selection_end = actpos;
817 result = UNDISPATCHED;
820 if (result != FINISHED) {
821 if (!the_locking_inset)
824 bv->unlockInset(this);
829 int InsetText::Latex(ostream &os, signed char fragile) const
833 int i = Latex(fstr, fragile);
839 int InsetText::Latex(string & file, signed char /* fragile */) const
843 return par->SimpleTeXOnePar(file, texrow);
847 void InsetText::Validate(LaTeXFeatures & features) const
849 par->validate(features);
853 // Returns the width of a character at a certain spot
854 int InsetText::SingleWidth(Painter & pain, LyXParagraph * par, int pos) const
856 LyXFont font = GetFont(par, pos);
857 char c = par->GetChar(pos);
859 if (IsPrintable(c)) {
860 return font.width(c);
861 } else if (c == LyXParagraph::META_INSET) {
862 Inset const * tmpinset=par->GetInset(pos);
864 return tmpinset->width(pain, font);
867 } else if (IsSeparatorChar(c))
869 else if (IsNewlineChar(c))
871 return font.width(c);
875 // Returns the width of a character at a certain spot
876 void InsetText::SingleHeight(Painter & pain, LyXParagraph * par,int pos,
877 int & asc, int & desc) const
879 LyXFont font = GetFont(par, pos);
880 char c = par->GetChar(pos);
883 if (c == LyXParagraph::META_INSET) {
884 Inset const * tmpinset=par->GetInset(pos);
886 asc = tmpinset->ascent(pain, font);
887 desc = tmpinset->descent(pain, font);
890 asc = font.maxAscent();
891 desc = font.maxDescent();
897 // Gets the fully instantiated font at a given position in a paragraph
898 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
899 // The difference is that this one is used for displaying, and thus we
900 // are allowed to make cosmetic improvements. For instance make footnotes
902 // If position is -1, we get the layout font of the paragraph.
903 // If position is -2, we get the font of the manual label of the paragraph.
904 LyXFont InsetText::GetFont(LyXParagraph * par, int pos) const
906 char par_depth = par->GetDepth();
909 textclasslist.Style(buffer->params.textclass, par->GetLayout());
911 // We specialize the 95% common case:
912 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
915 if (layout.labeltype == LABEL_MANUAL
916 && pos < BeginningOfMainBody(par)) {
918 return par->GetFontSettings(pos).realize(layout.reslabelfont);
920 return par->GetFontSettings(pos).realize(layout.resfont);
923 // process layoutfont for pos == -1 and labelfont for pos < -1
925 return layout.resfont;
927 return layout.reslabelfont;
930 // The uncommon case need not be optimized as much
932 LyXFont layoutfont, tmpfont;
936 if (pos < BeginningOfMainBody(par)) {
938 layoutfont = layout.labelfont;
941 layoutfont = layout.font;
943 tmpfont = par->GetFontSettings(pos);
944 tmpfont.realize(layoutfont);
947 // process layoutfont for pos == -1 and labelfont for pos < -1
949 tmpfont = layout.font;
951 tmpfont = layout.labelfont;
954 // Resolve against environment font information
955 //if (par->GetDepth()){ // already in while condition
956 while (par && par_depth && !tmpfont.resolved()) {
957 par = par->DepthHook(par_depth - 1);
959 tmpfont.realize(textclasslist.Style(buffer->params.textclass,
960 par->GetLayout()).font);
961 par_depth = par->GetDepth();
964 tmpfont.realize((textclasslist.TextClass(buffer->params.textclass).
970 int InsetText::BeginningOfMainBody(LyXParagraph * par) const
972 if (textclasslist.Style(buffer->params.textclass,
973 par->GetLayout()).labeltype != LABEL_MANUAL)
976 return par->BeginningOfMainBody();
980 void InsetText::GetCursorPos(int & x, int & y) const
987 int InsetText::InsetInInsetY()
989 if (!the_locking_inset)
994 return (y + the_locking_inset->InsetInInsetY());
998 void InsetText::ToggleInsetCursor(BufferView * bv)
1000 if (the_locking_inset) {
1001 the_locking_inset->ToggleInsetCursor(bv);
1005 LyXFont font = GetFont(par, actpos);
1007 int asc = font.maxAscent();
1008 int desc = font.maxDescent();
1011 bv->hideLockedInsetCursor();
1013 bv->showLockedInsetCursor(cx, cy, asc, desc);
1014 cursor_visible = !cursor_visible;
1018 void InsetText::ShowInsetCursor(BufferView * bv)
1020 if (!cursor_visible) {
1021 LyXFont font = GetFont(par, actpos);
1023 int asc = font.maxAscent();
1024 int desc = font.maxDescent();
1025 bv->fitLockedInsetCursor(cx, cy, asc, desc);
1026 bv->showLockedInsetCursor(cx, cy, asc, desc);
1027 cursor_visible = true;
1032 void InsetText::HideInsetCursor(BufferView * bv)
1035 ToggleInsetCursor(bv);
1039 void InsetText::setPos(BufferView * bv, int x, int y, bool activate_inset)
1043 // search right X-pos x==0 -> top_x
1044 actpos = actrow = 0;
1047 for(unsigned int i = 1;
1048 ((cy + rows[i - 1].desc) < y) && (i < rows.size() - 1); ++i) {
1049 cy = rows[i].baseline;
1050 actpos = rows[i].pos;
1058 int sw = swh = SingleWidth(bv->getPainter(), par,actpos);
1059 if (par->GetChar(actpos)!=LyXParagraph::META_INSET)
1061 while ((actpos < (rows[actrow + 1].pos - 1)) && ((cx + swh) < x)) {
1064 sw = swh = SingleWidth(bv->getPainter(), par,actpos);
1065 if (par->GetChar(actpos)!=LyXParagraph::META_INSET)
1068 if (activate_inset && par->GetChar(actpos)==LyXParagraph::META_INSET) {
1070 static_cast<UpdatableInset*>(par->GetInset(actpos));
1071 inset_x = cx - top_x;
1074 the_locking_inset->Edit(bv, ox - inset_x, oy - inset_y, 0);
1079 bool InsetText::moveRight(BufferView * bv, bool activate_inset)
1081 if (actpos >= par->Last())
1083 if (activate_inset && par->GetChar(actpos)==LyXParagraph::META_INSET) {
1085 static_cast<UpdatableInset*>(par->GetInset(actpos));
1086 inset_x = cx - top_x;
1089 the_locking_inset->Edit(bv, 0, 0, 0);
1098 bool InsetText::moveLeft(BufferView * bv, bool activate_inset)
1103 if (activate_inset && par->GetChar(actpos)==LyXParagraph::META_INSET) {
1105 static_cast<UpdatableInset*>(par->GetInset(actpos));
1107 inset_x = cx - top_x;
1110 the_locking_inset->Edit(bv, the_locking_inset->
1111 width(bv->getPainter(), GetFont(par,actpos)),
1120 bool InsetText::moveUp(BufferView * bv, bool activate_inset)
1124 cy = rows[actrow - 1].baseline - top_baseline;
1125 setPos(bv, cx - top_x, cy, activate_inset);
1130 bool InsetText::moveDown(BufferView * bv, bool activate_inset)
1132 if (actrow >= int(rows.size() - 2))
1134 cy = rows[actrow + 1].baseline - top_baseline;
1135 setPos(bv, cx - top_x, cy, activate_inset);
1140 void InsetText::resetPos(BufferView * bv)
1142 int old_pos = actpos;
1146 for(int i = 0; rows[i].pos <= actpos; ++i) {
1147 cy = rows[i].baseline;
1151 setPos(bv, 0, cy, false);
1153 while(actpos < old_pos) {
1154 cx += SingleWidth(bv->getPainter(), par,actpos);
1160 bool InsetText::Delete()
1162 /* some insets are undeletable here */
1163 if (par->GetChar(actpos)==LyXParagraph::META_INSET) {
1164 /* force complete redo when erasing display insets */
1165 /* this is a cruel mathod but save..... Matthias */
1166 if (par->GetInset(actpos)->Deletable() &&
1167 par->GetInset(actpos)->display()) {
1178 bool InsetText::InsertInset(BufferView * bv, Inset * inset)
1180 par->InsertChar(actpos, LyXParagraph::META_INSET);
1181 par->InsertInset(actpos, inset);
1182 computeTextRows(bv->getPainter());
1183 bv->updateInset(this, true);
1184 the_locking_inset = static_cast<UpdatableInset*>(inset);
1185 inset_x = cx - top_x;
1188 inset->Edit(bv, 0, 0, 0);
1193 UpdatableInset * InsetText::GetLockingInset()
1195 return the_locking_inset ? the_locking_inset->GetLockingInset() : this;
1199 void InsetText::SetFont(BufferView * bv, LyXFont const & font, bool toggleall)
1201 // if there is no selection just set the current_font
1202 if (!hasSelection()) {
1203 // Determine basis font
1205 if (actpos < BeginningOfMainBody(par))
1206 layoutfont = GetFont(par, -2);
1208 layoutfont = GetFont(par, -1);
1210 // Update current font
1211 real_current_font.update(font, toggleall);
1213 // Reduce to implicit settings
1214 current_font = real_current_font;
1215 current_font.reduce(layoutfont);
1216 // And resolve it completely
1217 real_current_font.realize(layoutfont);
1222 if (selection_start > selection_end) {
1223 s_start = selection_end;
1224 s_end = selection_start;
1226 s_start = selection_start;
1227 s_end = selection_end;
1230 while(s_start < s_end) {
1231 newfont = GetFont(par,s_start);
1232 newfont.update(font, toggleall);
1233 SetCharFont(s_start, newfont);
1236 computeTextRows(bv->getPainter());
1237 bv->updateInset(this, true);
1241 void InsetText::SetCharFont(int pos, LyXFont const & f)
1243 /* let the insets convert their font */
1246 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
1247 if (par->GetInset(pos))
1248 font = par->GetInset(pos)->ConvertFont(font);
1251 textclasslist.Style(buffer->params.textclass,par->GetLayout());
1253 // Get concrete layout font to reduce against
1256 if (pos < BeginningOfMainBody(par))
1257 layoutfont = layout.labelfont;
1259 layoutfont = layout.font;
1262 layoutfont.realize((textclasslist.TextClass(buffer->params.textclass).
1265 // Now, reduce font against full layout font
1266 font.reduce(layoutfont);
1268 par->SetFont(pos, font);
1272 void InsetText::computeTextRows(Painter & pain) const
1286 rows.erase(rows.begin(),rows.end());
1287 int width = wordAscent = wordDescent = 0;
1288 insetWidth = maxAscent = maxDescent = 0;
1293 rows.push_back(row);
1295 for(p=0; p < par->Last(); ++p) {
1296 insetWidth += SingleWidth(pain, par, p);
1297 SingleHeight(pain, par, p, asc, desc);
1298 if (asc > maxAscent)
1300 if (desc > maxDescent)
1303 rows[0].asc = maxAscent;
1304 rows[0].desc = maxDescent;
1305 // alocate a dummy row for the endpos
1306 row.pos = par->Last();
1307 rows.push_back(row);
1310 bool is_first_word_in_row = true;
1315 for(p = 0; p < par->Last(); ++p) {
1316 cw = SingleWidth(pain, par, p);
1318 lastWordWidth += cw;
1319 SingleHeight(pain, par, p, asc, desc);
1320 if (asc > wordAscent)
1322 if (desc > wordDescent)
1324 Inset const * inset = 0;
1325 if (((p + 1) < par->Last()) &&
1326 (par->GetChar(p+1)==LyXParagraph::META_INSET))
1327 inset = par->GetInset(p+1);
1328 if (inset && inset->display()) {
1329 if (!is_first_word_in_row && (width >= maxWidth)) {
1330 // we have to split also the row above
1331 rows[rows.size()-1].asc = oasc;
1332 rows[rows.size()-1].desc = odesc;
1334 rows.push_back(row);
1336 odesc = wordDescent;
1337 if (insetWidth < owidth)
1338 insetWidth = owidth;
1339 width = lastWordWidth;
1342 if (oasc < wordAscent)
1344 if (odesc < wordDescent)
1345 odesc = wordDescent;
1347 rows[rows.size() - 1].asc = oasc;
1348 rows[rows.size() - 1].desc = odesc;
1350 rows.push_back(row);
1351 SingleHeight(pain, par, p, asc, desc);
1352 rows[rows.size() - 1].asc = asc;
1353 rows[rows.size() - 1].desc = desc;
1354 row.pos = nwp = p + 1;
1355 rows.push_back(row);
1356 oasc = odesc = width = lastWordWidth = 0;
1357 is_first_word_in_row = true;
1358 wordAscent = wordDescent = 0;
1360 } else if (par->IsSeparator(p)) {
1361 if (width >= maxWidth) {
1362 if (is_first_word_in_row) {
1363 rows[rows.size()-1].asc = wordAscent;
1364 rows[rows.size()-1].desc = wordDescent;
1366 rows.push_back(row);
1367 oasc = odesc = width = 0;
1369 rows[rows.size()-1].asc = oasc;
1370 rows[rows.size()-1].desc = odesc;
1372 rows.push_back(row);
1374 odesc = wordDescent;
1375 if (insetWidth < owidth)
1376 insetWidth = owidth;
1377 width = lastWordWidth;
1379 wordAscent = wordDescent = lastWordWidth = 0;
1384 if (oasc < wordAscent)
1386 if (odesc < wordDescent)
1387 odesc = wordDescent;
1388 wordAscent = wordDescent = lastWordWidth = 0;
1390 is_first_word_in_row = false;
1393 // if we have some data in the paragraph we have ascent/descent
1395 if (width >= maxWidth) {
1397 rows[rows.size()-1].asc = oasc;
1398 rows[rows.size()-1].desc = odesc;
1399 // assign and allocate lower row
1401 rows.push_back(row);
1402 rows[rows.size()-1].asc = wordAscent;
1403 rows[rows.size()-1].desc = wordDescent;
1404 if (insetWidth < owidth)
1405 insetWidth = owidth;
1407 if (insetWidth < width)
1410 // assign last row data
1411 if (oasc < wordAscent)
1413 if (odesc < wordDescent)
1414 odesc = wordDescent;
1415 rows[rows.size()-1].asc = oasc;
1416 rows[rows.size()-1].desc = odesc;
1419 // alocate a dummy row for the endpos
1420 row.pos = par->Last();
1421 rows.push_back(row);
1422 // calculate maxAscent/Descent
1423 maxAscent = rows[0].asc;
1424 maxDescent = rows[0].desc;
1425 for (unsigned int i=1; i<rows.size()-1; ++i) {
1426 maxDescent += rows[i].asc + rows[i].desc + interline_space;
1429 if (the_locking_inset) {
1430 computeBaselines(top_baseline);
1440 void InsetText::computeBaselines(int baseline) const
1442 rows[0].baseline = baseline;
1443 for (unsigned int i=1; i<rows.size()-1; i++) {
1444 rows[i].baseline = rows[i-1].baseline + rows[i-1].desc +
1445 rows[i].asc + interline_space;