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 InsetText * 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;
818 result = UNDISPATCHED;
821 if (result != FINISHED) {
822 if (!the_locking_inset)
825 bv->unlockInset(this);
830 int InsetText::Latex(ostream &os, signed char fragile) const
834 int i = Latex(fstr, fragile);
840 int InsetText::Latex(string & file, signed char /* fragile */) const
844 return par->SimpleTeXOnePar(file, texrow);
848 void InsetText::Validate(LaTeXFeatures & features) const
850 par->validate(features);
854 // Returns the width of a character at a certain spot
855 int InsetText::SingleWidth(Painter & pain, LyXParagraph * par, int pos) const
857 LyXFont font = GetFont(par, pos);
858 char c = par->GetChar(pos);
860 if (IsPrintable(c)) {
861 return font.width(c);
862 } else if (c == LyXParagraph::META_INSET) {
863 Inset const * tmpinset=par->GetInset(pos);
865 return tmpinset->width(pain, font);
868 } else if (IsSeparatorChar(c))
870 else if (IsNewlineChar(c))
872 return font.width(c);
876 // Returns the width of a character at a certain spot
877 void InsetText::SingleHeight(Painter & pain, LyXParagraph * par,int pos,
878 int & asc, int & desc) const
880 LyXFont font = GetFont(par, pos);
881 char c = par->GetChar(pos);
884 if (c == LyXParagraph::META_INSET) {
885 Inset const * tmpinset=par->GetInset(pos);
887 asc = tmpinset->ascent(pain, font);
888 desc = tmpinset->descent(pain, font);
891 asc = font.maxAscent();
892 desc = font.maxDescent();
898 // Gets the fully instantiated font at a given position in a paragraph
899 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
900 // The difference is that this one is used for displaying, and thus we
901 // are allowed to make cosmetic improvements. For instance make footnotes
903 // If position is -1, we get the layout font of the paragraph.
904 // If position is -2, we get the font of the manual label of the paragraph.
905 LyXFont InsetText::GetFont(LyXParagraph * par, int pos) const
907 char par_depth = par->GetDepth();
910 textclasslist.Style(buffer->params.textclass, par->GetLayout());
912 // We specialize the 95% common case:
913 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
916 if (layout.labeltype == LABEL_MANUAL
917 && pos < BeginningOfMainBody(par)) {
919 return par->GetFontSettings(pos).realize(layout.reslabelfont);
921 return par->GetFontSettings(pos).realize(layout.resfont);
924 // process layoutfont for pos == -1 and labelfont for pos < -1
926 return layout.resfont;
928 return layout.reslabelfont;
931 // The uncommon case need not be optimized as much
933 LyXFont layoutfont, tmpfont;
937 if (pos < BeginningOfMainBody(par)) {
939 layoutfont = layout.labelfont;
942 layoutfont = layout.font;
944 tmpfont = par->GetFontSettings(pos);
945 tmpfont.realize(layoutfont);
948 // process layoutfont for pos == -1 and labelfont for pos < -1
950 tmpfont = layout.font;
952 tmpfont = layout.labelfont;
955 // Resolve against environment font information
956 //if (par->GetDepth()){ // already in while condition
957 while (par && par_depth && !tmpfont.resolved()) {
958 par = par->DepthHook(par_depth - 1);
960 tmpfont.realize(textclasslist.Style(buffer->params.textclass,
961 par->GetLayout()).font);
962 par_depth = par->GetDepth();
965 tmpfont.realize((textclasslist.TextClass(buffer->params.textclass).
971 int InsetText::BeginningOfMainBody(LyXParagraph * par) const
973 if (textclasslist.Style(buffer->params.textclass,
974 par->GetLayout()).labeltype != LABEL_MANUAL)
977 return par->BeginningOfMainBody();
981 void InsetText::GetCursorPos(int & x, int & y)
988 int InsetText::InsetInInsetY()
990 if (!the_locking_inset)
995 return (y + the_locking_inset->InsetInInsetY());
999 void InsetText::ToggleInsetCursor(BufferView * bv)
1001 if (the_locking_inset) {
1002 the_locking_inset->ToggleInsetCursor(bv);
1006 LyXFont font = GetFont(par, actpos);
1008 int asc = font.maxAscent();
1009 int desc = font.maxDescent();
1012 bv->hideLockedInsetCursor();
1014 bv->showLockedInsetCursor(cx, cy, asc, desc);
1015 cursor_visible = !cursor_visible;
1019 void InsetText::ShowInsetCursor(BufferView * bv)
1021 if (!cursor_visible) {
1022 LyXFont font = GetFont(par, actpos);
1024 int asc = font.maxAscent();
1025 int desc = font.maxDescent();
1026 bv->fitLockedInsetCursor(cx, cy, asc, desc);
1027 bv->showLockedInsetCursor(cx, cy, asc, desc);
1028 cursor_visible = true;
1033 void InsetText::HideInsetCursor(BufferView * bv)
1036 ToggleInsetCursor(bv);
1040 void InsetText::setPos(BufferView * bv, int x, int y, bool activate_inset)
1044 // search right X-pos x==0 -> top_x
1045 actpos = actrow = 0;
1048 for(unsigned int i = 1;
1049 ((cy + rows[i - 1].desc) < y) && (i < rows.size() - 1); ++i) {
1050 cy = rows[i].baseline;
1051 actpos = rows[i].pos;
1059 int sw = swh = SingleWidth(bv->getPainter(), par,actpos);
1060 if (par->GetChar(actpos)!=LyXParagraph::META_INSET)
1062 while ((actpos < (rows[actrow + 1].pos - 1)) && ((cx + swh) < x)) {
1065 sw = swh = SingleWidth(bv->getPainter(), par,actpos);
1066 if (par->GetChar(actpos)!=LyXParagraph::META_INSET)
1069 if (activate_inset && par->GetChar(actpos)==LyXParagraph::META_INSET) {
1071 static_cast<UpdatableInset*>(par->GetInset(actpos));
1072 inset_x = cx - top_x;
1075 the_locking_inset->Edit(bv, ox - inset_x, oy - inset_y, 0);
1080 bool InsetText::moveRight(BufferView * bv, bool activate_inset)
1082 if (actpos >= par->Last())
1084 if (activate_inset && par->GetChar(actpos)==LyXParagraph::META_INSET) {
1086 static_cast<UpdatableInset*>(par->GetInset(actpos));
1087 inset_x = cx - top_x;
1090 the_locking_inset->Edit(bv, 0, 0, 0);
1099 bool InsetText::moveLeft(BufferView * bv, bool activate_inset)
1104 if (activate_inset && par->GetChar(actpos)==LyXParagraph::META_INSET) {
1106 static_cast<UpdatableInset*>(par->GetInset(actpos));
1108 inset_x = cx - top_x;
1111 the_locking_inset->Edit(bv, the_locking_inset->
1112 width(bv->getPainter(), GetFont(par,actpos)),
1121 bool InsetText::moveUp(BufferView * bv, bool activate_inset)
1125 cy = rows[actrow - 1].baseline - top_baseline;
1126 setPos(bv, cx - top_x, cy, activate_inset);
1131 bool InsetText::moveDown(BufferView * bv, bool activate_inset)
1133 if (actrow >= int(rows.size() - 2))
1135 cy = rows[actrow + 1].baseline - top_baseline;
1136 setPos(bv, cx - top_x, cy, activate_inset);
1141 void InsetText::resetPos(BufferView * bv)
1143 int old_pos = actpos;
1147 for(int i = 0; rows[i].pos <= actpos; ++i) {
1148 cy = rows[i].baseline;
1152 setPos(bv, 0, cy, false);
1154 while(actpos < old_pos) {
1155 cx += SingleWidth(bv->getPainter(), par,actpos);
1161 bool InsetText::Delete()
1163 /* some insets are undeletable here */
1164 if (par->GetChar(actpos)==LyXParagraph::META_INSET) {
1165 /* force complete redo when erasing display insets */
1166 /* this is a cruel mathod but save..... Matthias */
1167 if (par->GetInset(actpos)->Deletable() &&
1168 par->GetInset(actpos)->display()) {
1179 bool InsetText::InsertInset(BufferView * bv, Inset * inset)
1181 par->InsertChar(actpos, LyXParagraph::META_INSET);
1182 par->InsertInset(actpos, inset);
1183 computeTextRows(bv->getPainter());
1184 bv->updateInset(this, true);
1185 the_locking_inset = static_cast<UpdatableInset*>(inset);
1186 inset_x = cx - top_x;
1189 inset->Edit(bv, 0, 0, 0);
1194 UpdatableInset * InsetText::GetLockingInset()
1196 return the_locking_inset ? the_locking_inset->GetLockingInset() : this;
1200 void InsetText::SetFont(BufferView * bv, LyXFont const & font, bool toggleall)
1202 // if there is no selection just set the current_font
1203 if (!hasSelection()) {
1204 // Determine basis font
1206 if (actpos < BeginningOfMainBody(par))
1207 layoutfont = GetFont(par, -2);
1209 layoutfont = GetFont(par, -1);
1211 // Update current font
1212 real_current_font.update(font, toggleall);
1214 // Reduce to implicit settings
1215 current_font = real_current_font;
1216 current_font.reduce(layoutfont);
1217 // And resolve it completely
1218 real_current_font.realize(layoutfont);
1223 if (selection_start > selection_end) {
1224 s_start = selection_end;
1225 s_end = selection_start;
1227 s_start = selection_start;
1228 s_end = selection_end;
1231 while(s_start < s_end) {
1232 newfont = GetFont(par,s_start);
1233 newfont.update(font, toggleall);
1234 SetCharFont(s_start, newfont);
1237 computeTextRows(bv->getPainter());
1238 bv->updateInset(this, true);
1242 void InsetText::SetCharFont(int pos, LyXFont const & f)
1244 /* let the insets convert their font */
1247 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
1248 if (par->GetInset(pos))
1249 font = par->GetInset(pos)->ConvertFont(font);
1252 textclasslist.Style(buffer->params.textclass,par->GetLayout());
1254 // Get concrete layout font to reduce against
1257 if (pos < BeginningOfMainBody(par))
1258 layoutfont = layout.labelfont;
1260 layoutfont = layout.font;
1263 layoutfont.realize((textclasslist.TextClass(buffer->params.textclass).
1266 // Now, reduce font against full layout font
1267 font.reduce(layoutfont);
1269 par->SetFont(pos, font);
1273 void InsetText::computeTextRows(Painter & pain) const
1287 rows.erase(rows.begin(),rows.end());
1288 int width = wordAscent = wordDescent = 0;
1289 insetWidth = maxAscent = maxDescent = 0;
1294 rows.push_back(row);
1296 for(p=0; p < par->Last(); ++p) {
1297 insetWidth += SingleWidth(pain, par, p);
1298 SingleHeight(pain, par, p, asc, desc);
1299 if (asc > maxAscent)
1301 if (desc > maxDescent)
1304 rows[0].asc = maxAscent;
1305 rows[0].desc = maxDescent;
1306 // alocate a dummy row for the endpos
1307 row.pos = par->Last();
1308 rows.push_back(row);
1311 bool is_first_word_in_row = true;
1316 for(p = 0; p < par->Last(); ++p) {
1317 cw = SingleWidth(pain, par, p);
1319 lastWordWidth += cw;
1320 SingleHeight(pain, par, p, asc, desc);
1321 if (asc > wordAscent)
1323 if (desc > wordDescent)
1325 Inset const * inset = 0;
1326 if (((p + 1) < par->Last()) &&
1327 (par->GetChar(p+1)==LyXParagraph::META_INSET))
1328 inset = par->GetInset(p+1);
1329 if (inset && inset->display()) {
1330 if (!is_first_word_in_row && (width >= maxWidth)) {
1331 // we have to split also the row above
1332 rows[rows.size()-1].asc = oasc;
1333 rows[rows.size()-1].desc = odesc;
1335 rows.push_back(row);
1337 odesc = wordDescent;
1338 if (insetWidth < owidth)
1339 insetWidth = owidth;
1340 width = lastWordWidth;
1343 if (oasc < wordAscent)
1345 if (odesc < wordDescent)
1346 odesc = wordDescent;
1348 rows[rows.size() - 1].asc = oasc;
1349 rows[rows.size() - 1].desc = odesc;
1351 rows.push_back(row);
1352 SingleHeight(pain, par, p, asc, desc);
1353 rows[rows.size() - 1].asc = asc;
1354 rows[rows.size() - 1].desc = desc;
1355 row.pos = nwp = p + 1;
1356 rows.push_back(row);
1357 oasc = odesc = width = lastWordWidth = 0;
1358 is_first_word_in_row = true;
1359 wordAscent = wordDescent = 0;
1361 } else if (par->IsSeparator(p)) {
1362 if (width >= maxWidth) {
1363 if (is_first_word_in_row) {
1364 rows[rows.size()-1].asc = wordAscent;
1365 rows[rows.size()-1].desc = wordDescent;
1367 rows.push_back(row);
1368 oasc = odesc = width = 0;
1370 rows[rows.size()-1].asc = oasc;
1371 rows[rows.size()-1].desc = odesc;
1373 rows.push_back(row);
1375 odesc = wordDescent;
1376 if (insetWidth < owidth)
1377 insetWidth = owidth;
1378 width = lastWordWidth;
1380 wordAscent = wordDescent = lastWordWidth = 0;
1385 if (oasc < wordAscent)
1387 if (odesc < wordDescent)
1388 odesc = wordDescent;
1389 wordAscent = wordDescent = lastWordWidth = 0;
1391 is_first_word_in_row = false;
1394 // if we have some data in the paragraph we have ascent/descent
1396 if (width >= maxWidth) {
1398 rows[rows.size()-1].asc = oasc;
1399 rows[rows.size()-1].desc = odesc;
1400 // assign and allocate lower row
1402 rows.push_back(row);
1403 rows[rows.size()-1].asc = wordAscent;
1404 rows[rows.size()-1].desc = wordDescent;
1405 if (insetWidth < owidth)
1406 insetWidth = owidth;
1408 if (insetWidth < width)
1411 // assign last row data
1412 if (oasc < wordAscent)
1414 if (odesc < wordDescent)
1415 odesc = wordDescent;
1416 rows[rows.size()-1].asc = oasc;
1417 rows[rows.size()-1].desc = odesc;
1420 // alocate a dummy row for the endpos
1421 row.pos = par->Last();
1422 rows.push_back(row);
1423 // calculate maxAscent/Descent
1424 maxAscent = rows[0].asc;
1425 maxDescent = rows[0].desc;
1426 for (unsigned int i=1; i<rows.size()-1; ++i) {
1427 maxDescent += rows[i].asc + rows[i].desc + interline_space;
1430 if (the_locking_inset) {
1431 computeBaselines(top_baseline);
1441 void InsetText::computeBaselines(int baseline) const
1443 rows[0].baseline = baseline;
1444 for (unsigned int i=1; i<rows.size()-1; i++) {
1445 rows[i].baseline = rows[i-1].baseline + rows[i-1].desc +
1446 rows[i].asc + interline_space;