2 /* This file is part of
3 * ======================================================
5 * LyX, The Document Processor
7 * Copyright (C) 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 // The following three are only for compatibility
318 if (inscmd.getCmdName()=="-") {
319 inset = new InsetSpecialChar(InsetSpecialChar::HYPHENATION);
320 } else if (inscmd.getCmdName()=="@.") {
321 inset = new InsetSpecialChar(InsetSpecialChar::END_OF_SENTENCE);
322 } else if (inscmd.getCmdName()=="ldots") {
323 inset = new InsetSpecialChar(InsetSpecialChar::LDOTS);
325 inset = inscmd.Clone();
328 par->InsertChar(pos, LyXParagraph::META_INSET);
329 par->InsertInset(pos, inset);
330 par->SetFont(pos, font);
333 lex.printError("Unknown inset `$$Token'. "
334 "Inserting as text.");
336 #ifndef NO_COMPABILITY
337 } else if (token == "\\hfill") {
338 // now obsolete, but we have a bak compability
339 // Inset * inset = new InsetSpecialChar(LyXParagraph::META_HFILL);
340 // par->InsertChar(pos, LyXParagraph::META_INSET);
341 // par->InsertInset(pos, inset);
342 par->InsertChar(pos, LyXParagraph::META_HFILL);
343 par->SetFont(pos, font);
345 } else if (token == "\\protected_separator") {
346 // now obsolete, but we have a back compability
347 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
348 //Inset * inset = new InsetSpecialChar(LyXParagraph::META_PROTECTED_SEPARATOR);
349 // par->InsertChar(pos, LyXParagraph::META_INSET);
350 // par->InsertInset(pos, inset);
351 par->SetFont(pos, font);
354 } else if (token == "\\bibitem") { // ale970302
356 par->bibkey = new InsetBibKey;
357 par->bibkey->Read(lex);
358 }else if (token == "\\backslash") {
359 par->InsertChar(pos, '\\');
360 par->SetFont(pos, font);
362 } else if (token == "\\end_inset") {
365 lex.printError("Unknown tabular token `$$Token'. Not handled!");
369 if (token != "\\end_inset") {
370 lex.printError("Missing \\end_inset at this point. "
377 int InsetText::ascent(Painter &, LyXFont const & font) const
381 return font.maxAscent();
385 int InsetText::descent(Painter &, LyXFont const & font) const
389 return font.maxDescent();
393 int InsetText::width(Painter &, LyXFont const &) const
399 int InsetText::getMaxWidth(UpdatableInset * inset) const
401 if (!the_locking_inset) {
402 lyxerr << "Text: No locking inset in this inset.\n";
406 if (the_locking_inset==inset)
409 return the_locking_inset->getMaxWidth(inset);
413 void InsetText::draw(Painter & pain,const LyXFont & f,int baseline,float & x) const
420 UpdatableInset::draw(pain, f, baseline, x);
421 do_reset_pos = (x != top_x) || (baseline != top_baseline);
423 top_baseline = baseline;
424 computeBaselines(baseline);
425 for(r=0; r<rows.size()-1; ++r) {
426 drawRowSelection(pain, rows[r].pos, rows[r+1].pos, r,
427 rows[r].baseline, x);
428 drawRowText(pain, rows[r].pos, rows[r+1].pos, rows[r].baseline, x);
431 if (!the_locking_inset && do_reset_pos) {
432 // HideInsetCursor(bv);
434 // ShowInsetCursor(bv);
439 void InsetText::drawRowSelection(Painter & pain, int startpos, int endpos,
440 int row, int baseline, float x) const
453 if (selection_start > selection_end) {
454 s_start = selection_end;
455 s_end = selection_start;
457 s_start = selection_start;
458 s_end = selection_end;
460 if ((s_start > endpos) || (s_end < startpos))
462 ssel_x = esel_x = int(x);
463 for(p=startpos; p < endpos; ++p) {
466 if ((p >= s_start) && (p <= s_end))
468 ch = par->GetChar(p);
469 font = GetFont(par,p);
470 if (IsFloatChar(ch)) {
472 } else if (ch == LyXParagraph::META_INSET) {
473 Inset const * tmpinset = par->GetInset(p);
474 x += tmpinset->width(pain, font);
476 x += pain.width(ch,font);
481 if ((p >= s_start) && (p <= s_end))
483 if (ssel_x < esel_x) {
484 pain.fillRectangle(int(ssel_x), baseline-rows[row].asc,
485 int(esel_x - ssel_x),
486 rows[row].asc + rows[row].desc,
492 void InsetText::drawRowText(Painter & pain, int startpos, int endpos,
493 int baseline, float x) const
495 Assert(endpos <= par->Last());
502 for(p=startpos; p < endpos; ++p) {
503 ch = par->GetChar(p);
504 font = GetFont(par,p);
505 if (IsFloatChar(ch)) {
507 } else if (ch == LyXParagraph::META_INSET) {
508 Inset * tmpinset = par->GetInset(p);
510 tmpinset->draw(pain, font, baseline, x);
512 pain.text(int(x), baseline, ch, font);
513 x += pain.width(ch,font);
519 const char * InsetText::EditMessage() const
521 return _("Opened Text Inset");
525 void InsetText::Edit(BufferView * bv, int x, int y, unsigned int button)
527 UpdatableInset::Edit(bv, x, y, button);
530 the_locking_inset = 0;
531 inset_pos = inset_x = inset_y = 0;
534 selection_start = selection_end = actpos;
535 current_font = real_current_font = GetFont(par, actpos);
539 void InsetText::InsetUnlock(BufferView *bv)
541 if (the_locking_inset)
542 the_locking_inset->InsetUnlock(bv);
544 if (hasSelection()) {
545 selection_start = selection_end = actpos;
546 bv->updateInset(this, false);
548 the_locking_inset = 0;
549 no_selection = false;
553 bool InsetText::UnlockInsetInInset(BufferView * bv, Inset * inset, bool lr)
555 if (!the_locking_inset)
557 if (the_locking_inset == inset) {
558 the_locking_inset->InsetUnlock(bv);
559 the_locking_inset = 0;
561 moveRight(bv, false);
564 return the_locking_inset->UnlockInsetInInset(bv, inset,lr);
567 bool InsetText::UpdateInsetInInset(BufferView * bv, Inset * inset)
569 if (!the_locking_inset)
571 if (the_locking_inset != inset)
572 return the_locking_inset->UpdateInsetInInset(bv, inset);
574 inset->draw(bv->getPainter(), real_current_font, inset_y, x);
575 bv->updateInset(this, true);
580 void InsetText::InsetButtonRelease(BufferView * bv, int x, int y, int button)
582 if (the_locking_inset) {
583 the_locking_inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
586 no_selection = false;
590 void InsetText::InsetButtonPress(BufferView * bv, int x, int y, int button)
592 if (hasSelection()) {
593 selection_start = selection_end = actpos;
594 bv->updateInset(this, false);
596 no_selection = false;
597 if (the_locking_inset) {
598 setPos(bv, x,y,false);
601 if (par->GetChar(actpos)==LyXParagraph::META_INSET)
602 inset=(UpdatableInset*)par->GetInset(actpos);
603 if (the_locking_inset == inset) {
604 the_locking_inset->InsetButtonPress(bv,x-inset_x,y-inset_y,button);
607 // otherwise unlock the_locking_inset and lock the new inset
611 the_locking_inset->InsetUnlock(bv);
612 the_locking_inset = inset;
613 the_locking_inset->Edit(bv, x - inset_x, y - inset_y, button);
616 // otherwise only unlock the_locking_inset
617 the_locking_inset->InsetUnlock(bv);
620 the_locking_inset = 0;
622 selection_start = selection_end = actpos;
623 if (!the_locking_inset)
628 void InsetText::InsetMotionNotify(BufferView * bv, int x, int y, int button)
630 if (the_locking_inset) {
631 the_locking_inset->InsetMotionNotify(bv, x-inset_x, y-inset_y,button);
637 setPos(bv, x, y, false);
638 selection_end = actpos;
639 if (old != selection_end)
640 bv->updateInset(this, false);
642 no_selection = false;
646 void InsetText::InsetKeyPress(XKeyEvent * xke)
648 if (the_locking_inset) {
649 the_locking_inset->InsetKeyPress(xke);
655 UpdatableInset::RESULT InsetText::LocalDispatch(BufferView * bv,
656 int action, string arg)
658 no_selection = false;
659 if (UpdatableInset::LocalDispatch(bv, action, arg)) {
664 UpdatableInset::RESULT
667 if ((action < 0) && arg.empty())
670 if ((action != LFUN_DOWN) && (action != LFUN_UP) &&
671 (action != LFUN_DOWNSEL) && (action != LFUN_UPSEL))
673 if (the_locking_inset) {
674 result = the_locking_inset->LocalDispatch(bv, action, arg);
675 if (result == DISPATCHED) {
676 the_locking_inset->ToggleInsetCursor(bv);
677 bv->updateInset(this, false);
678 the_locking_inset->ToggleInsetCursor(bv);
680 } else if (result == FINISHED) {
681 if ((action == LFUN_RIGHT) || (action == -1)) {
682 actpos = inset_pos + 1;
685 the_locking_inset = 0;
693 par->InsertChar(actpos,arg[0]);
694 par->SetFont(actpos,real_current_font);
696 bv->updateInset(this, true);
698 selection_start = selection_end = actpos;
701 // --- Cursor Movements ---------------------------------------------
703 moveRight(bv, false);
704 selection_end = actpos;
705 bv->updateInset(this, false);
708 result= DISPATCH_RESULT(moveRight(bv));
709 if (hasSelection()) {
710 selection_start = selection_end = actpos;
711 bv->updateInset(this, false);
713 selection_start = selection_end = actpos;
718 selection_end = actpos;
719 bv->updateInset(this, false);
722 result= DISPATCH_RESULT(moveLeft(bv));
723 if (hasSelection()) {
724 selection_start = selection_end = actpos;
725 bv->updateInset(this, false);
727 selection_start = selection_end = actpos;
732 selection_end = actpos;
733 bv->updateInset(this, false);
736 result= DISPATCH_RESULT(moveDown(bv));
737 if (hasSelection()) {
738 selection_start = selection_end = actpos;
739 bv->updateInset(this, false);
741 selection_start = selection_end = actpos;
746 selection_end = actpos;
747 bv->updateInset(this, false);
750 result= DISPATCH_RESULT(moveUp(bv));
751 if (hasSelection()) {
752 selection_start = selection_end = actpos;
753 bv->updateInset(this, false);
755 selection_start = selection_end = actpos;
759 if (!actpos || par->IsNewline(actpos-1)) {
760 if (hasSelection()) {
761 selection_start = selection_end = actpos;
762 bv->updateInset(this, false);
768 if (Delete()) { // we need update
769 selection_start = selection_end = actpos;
771 bv->updateInset(this, true);
772 } else if (hasSelection()) {
773 selection_start = selection_end = actpos;
774 bv->updateInset(this, false);
778 for(;actpos > rows[actrow].pos;--actpos)
779 cx -= SingleWidth(bv, par, actpos);
780 cx -= SingleWidth(bv, par, actpos);
781 if (hasSelection()) {
782 selection_start = selection_end = actpos;
783 bv->updateInset(this, false);
785 selection_start = selection_end = actpos;
789 for(;actpos < rows[actrow+1].pos;++actpos)
790 cx += SingleWidth(bv, par, actpos);
791 if (hasSelection()) {
792 selection_start = selection_end = actpos;
793 bv->updateInset(this, false);
795 selection_start = selection_end = actpos;
798 case LFUN_MATH_MODE: // Open or create a math inset
799 InsertInset(bv, new InsetFormula);
800 if (hasSelection()) {
801 selection_start = selection_end = actpos;
802 bv->updateInset(this, false);
804 selection_start = selection_end = actpos;
809 result = UNDISPATCHED;
812 if (result != FINISHED) {
813 if (!the_locking_inset)
816 bv->unlockInset(this);
821 int InsetText::Latex(ostream &os, signed char fragile) const
828 i = Latex(fstr, fragile);
834 int InsetText::Latex(string & file, signed char /* fragile */) const
839 return par->SimpleTeXOnePar(file, texrow);
843 void InsetText::Validate(LaTeXFeatures & features) const
845 par->validate(features);
849 // Returns the width of a character at a certain spot
850 int InsetText::SingleWidth(BufferView *bv, LyXParagraph * par, int pos)
853 font = GetFont(par, pos);
855 c = par->GetChar(pos);
857 // The most common case is handled first (Asger)
858 if (IsPrintable(c)) {
859 return font.width(c);
860 } else if (c == LyXParagraph::META_INSET) {
861 Inset const * tmpinset=par->GetInset(pos);
863 return tmpinset->width(bv->getPainter(), font);
866 } else if (IsSeparatorChar(c))
868 else if (IsNewlineChar(c))
870 return font.width(c);
874 // Returns the width of a character at a certain spot
875 void InsetText::SingleHeight(BufferView * bv, LyXParagraph * par,int pos,
876 int & asc, int & desc)
879 font = GetFont(par, pos);
881 c = par->GetChar(pos);
884 // The most common case is handled first (Asger)
885 if (c == LyXParagraph::META_INSET) {
886 Inset const * tmpinset=par->GetInset(pos);
888 asc = tmpinset->ascent(bv->getPainter(),font);
889 desc = tmpinset->descent(bv->getPainter(),font);
892 asc = font.maxAscent();
893 desc = font.maxDescent();
899 // Gets the fully instantiated font at a given position in a paragraph
900 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
901 // The difference is that this one is used for displaying, and thus we
902 // are allowed to make cosmetic improvements. For instance make footnotes
904 // If position is -1, we get the layout font of the paragraph.
905 // If position is -2, we get the font of the manual label of the paragraph.
906 LyXFont InsetText::GetFont(LyXParagraph * par, int pos) const
908 char par_depth = par->GetDepth();
911 textclasslist.Style(buffer->params.textclass, par->GetLayout());
913 // We specialize the 95% common case:
914 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
917 if (layout.labeltype == LABEL_MANUAL
918 && pos < BeginningOfMainBody(par)) {
920 return par->GetFontSettings(pos).realize(layout.reslabelfont);
922 return par->GetFontSettings(pos).realize(layout.resfont);
925 // process layoutfont for pos == -1 and labelfont for pos < -1
927 return layout.resfont;
929 return layout.reslabelfont;
932 // The uncommon case need not be optimized as much
934 LyXFont layoutfont, tmpfont;
938 if (pos < BeginningOfMainBody(par)) {
940 layoutfont = layout.labelfont;
943 layoutfont = layout.font;
945 tmpfont = par->GetFontSettings(pos);
946 tmpfont.realize(layoutfont);
949 // process layoutfont for pos == -1 and labelfont for pos < -1
951 tmpfont = layout.font;
953 tmpfont = layout.labelfont;
956 // Resolve against environment font information
957 //if (par->GetDepth()){ // already in while condition
958 while (par && par_depth && !tmpfont.resolved()) {
959 par = par->DepthHook(par_depth - 1);
961 tmpfont.realize(textclasslist.Style(buffer->params.textclass,
962 par->GetLayout()).font);
963 par_depth = par->GetDepth();
966 tmpfont.realize((textclasslist.TextClass(buffer->params.textclass).
972 int InsetText::BeginningOfMainBody(LyXParagraph * par) const
974 if (textclasslist.Style(buffer->params.textclass,
975 par->GetLayout()).labeltype != LABEL_MANUAL)
978 return par->BeginningOfMainBody();
982 void InsetText::GetCursorPos(int & x, int & y)
989 int InsetText::InsetInInsetY()
991 if (!the_locking_inset)
996 return (y + the_locking_inset->InsetInInsetY());
1000 void InsetText::ToggleInsetCursor(BufferView * bv)
1002 if (the_locking_inset) {
1003 the_locking_inset->ToggleInsetCursor(bv);
1009 font = GetFont(par, actpos);
1011 asc = font.maxAscent();
1012 desc = font.maxDescent();
1015 bv->hideLockedInsetCursor();
1017 bv->showLockedInsetCursor(cx, cy, asc, desc);
1018 cursor_visible = !cursor_visible;
1022 void InsetText::ShowInsetCursor(BufferView * bv)
1024 if (!cursor_visible) {
1028 font = GetFont(par, actpos);
1030 asc = font.maxAscent();
1031 desc = font.maxDescent();
1032 bv->fitLockedInsetCursor(cx, cy, asc, desc);
1033 bv->showLockedInsetCursor(cx, cy, asc, desc);
1034 cursor_visible = true;
1039 void InsetText::HideInsetCursor(BufferView * bv)
1042 ToggleInsetCursor(bv);
1046 void InsetText::setPos(BufferView * bv, int x, int y, bool activate_inset)
1051 // search right X-pos x==0 -> top_x
1052 actpos = actrow = 0;
1055 for(unsigned int i=1;
1056 ((cy+rows[i-1].desc) < y) && (i < rows.size()-1); ++i) {
1057 cy = rows[i].baseline;
1058 actpos = rows[i].pos;
1067 sw = swh = SingleWidth(bv, par,actpos);
1068 if (par->GetChar(actpos)!=LyXParagraph::META_INSET)
1070 while ((actpos < (rows[actrow+1].pos-1)) && ((cx+swh) < x)) {
1073 sw = swh = SingleWidth(bv, par,actpos);
1074 if (par->GetChar(actpos)!=LyXParagraph::META_INSET)
1077 if (activate_inset && par->GetChar(actpos)==LyXParagraph::META_INSET) {
1078 the_locking_inset=(UpdatableInset*)par->GetInset(actpos);
1082 the_locking_inset->Edit(bv, ox - inset_x, oy - inset_y, 0);
1087 bool InsetText::moveRight(BufferView * bv, bool activate_inset)
1089 if (actpos >= par->Last())
1091 if (activate_inset && par->GetChar(actpos)==LyXParagraph::META_INSET) {
1092 the_locking_inset=(UpdatableInset*)par->GetInset(actpos);
1096 the_locking_inset->Edit(bv, 0, 0, 0);
1105 bool InsetText::moveLeft(BufferView * bv, bool activate_inset)
1110 if (activate_inset && par->GetChar(actpos)==LyXParagraph::META_INSET) {
1111 the_locking_inset=(UpdatableInset*)par->GetInset(actpos);
1116 the_locking_inset->Edit(bv, the_locking_inset->
1117 width(bv->getPainter(),GetFont(par,actpos)),
1126 bool InsetText::moveUp(BufferView * bv, bool activate_inset)
1130 cy = rows[actrow-1].baseline - top_baseline;
1131 setPos(bv, cx-top_x, cy, activate_inset);
1136 bool InsetText::moveDown(BufferView * bv, bool activate_inset)
1138 if (actrow >= int(rows.size()-2))
1140 cy = rows[actrow+1].baseline - top_baseline;
1141 setPos(bv, cx-top_x, cy, activate_inset);
1146 void InsetText::resetPos(BufferView * bv)
1154 for(i=0; rows[i].pos <= actpos; ++i) {
1155 cy = rows[i].baseline;
1159 setPos(bv, 0, cy, false);
1161 while(actpos < old_pos) {
1162 cx += SingleWidth(bv, par,actpos);
1168 bool InsetText::Delete()
1170 /* some insets are undeletable here */
1171 if (par->GetChar(actpos)==LyXParagraph::META_INSET) {
1172 /* force complete redo when erasing display insets */
1173 /* this is a cruel mathod but save..... Matthias */
1174 if (par->GetInset(actpos)->Deletable() &&
1175 par->GetInset(actpos)->display()) {
1186 bool InsetText::InsertInset(BufferView * bv, Inset * inset)
1188 par->InsertChar(actpos, LyXParagraph::META_INSET);
1189 par->InsertInset(actpos, inset);
1190 computeTextRows(bv);
1191 bv->updateInset(this, true);
1192 the_locking_inset = (UpdatableInset*)inset;
1196 inset->Edit(bv, 0, 0, 0);
1201 UpdatableInset * InsetText::GetLockingInset()
1203 return the_locking_inset ? the_locking_inset->GetLockingInset() : this;
1207 void InsetText::SetFont(BufferView * bv, LyXFont const & font,bool toggleall)
1209 // if there is no selection just set the current_font
1210 if (!hasSelection()) {
1211 // Determine basis font
1213 if (actpos < BeginningOfMainBody(par))
1214 layoutfont = GetFont(par, -2);
1216 layoutfont = GetFont(par, -1);
1218 // Update current font
1219 real_current_font.update(font, toggleall);
1221 // Reduce to implicit settings
1222 current_font = real_current_font;
1223 current_font.reduce(layoutfont);
1224 // And resolve it completely
1225 real_current_font.realize(layoutfont);
1231 if (selection_start > selection_end) {
1232 s_start = selection_end;
1233 s_end = selection_start;
1235 s_start = selection_start;
1236 s_end = selection_end;
1240 while(s_start < s_end) {
1241 newfont = GetFont(par,s_start);
1242 newfont.update(font, toggleall);
1243 SetCharFont(s_start, newfont);
1246 computeTextRows(bv);
1247 bv->updateInset(this, true);
1251 void InsetText::SetCharFont(int pos, LyXFont font)
1253 /* let the insets convert their font */
1254 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
1255 if (par->GetInset(pos))
1256 font = par->GetInset(pos)->ConvertFont(font);
1259 textclasslist.Style(buffer->params.textclass,par->GetLayout());
1261 // Get concrete layout font to reduce against
1264 if (pos < BeginningOfMainBody(par))
1265 layoutfont = layout.labelfont;
1267 layoutfont = layout.font;
1270 layoutfont.realize((textclasslist.TextClass(buffer->params.textclass).
1273 // Now, reduce font against full layout font
1274 font.reduce(layoutfont);
1276 par->SetFont(pos, font);
1280 void InsetText::computeTextRows(BufferView * bv)
1297 rows.erase(rows.begin(),rows.end());
1298 width = wordAscent = wordDescent = 0;
1299 insetWidth = maxAscent = maxDescent = 0;
1304 rows.push_back(row);
1306 for(p=0; p < par->Last(); ++p) {
1307 insetWidth += SingleWidth(bv, par, p);
1308 SingleHeight(bv, par, p, asc, desc);
1309 if (asc > maxAscent)
1311 if (desc > maxDescent)
1314 rows[0].asc = maxAscent;
1315 rows[0].desc = maxDescent;
1316 // alocate a dummy row for the endpos
1317 row.pos = par->Last();
1318 rows.push_back(row);
1322 is_first_word_in_row = true;
1328 for(p = 0; p < par->Last(); ++p) {
1329 cw = SingleWidth(bv, par, p);
1331 lastWordWidth += cw;
1332 SingleHeight(bv, par, p, asc, desc);
1333 if (asc > wordAscent)
1335 if (desc > wordDescent)
1337 Inset const * inset = 0;
1338 if (((p + 1) < par->Last()) &&
1339 (par->GetChar(p+1)==LyXParagraph::META_INSET))
1340 inset = par->GetInset(p+1);
1341 if (inset && inset->display()) {
1342 if (!is_first_word_in_row && (width >= maxWidth)) {
1343 // we have to split also the row above
1344 rows[rows.size()-1].asc = oasc;
1345 rows[rows.size()-1].desc = odesc;
1347 rows.push_back(row);
1349 odesc = wordDescent;
1350 if (insetWidth < owidth)
1351 insetWidth = owidth;
1352 width = lastWordWidth;
1355 if (oasc < wordAscent)
1357 if (odesc < wordDescent)
1358 odesc = wordDescent;
1360 rows[rows.size() - 1].asc = oasc;
1361 rows[rows.size() - 1].desc = odesc;
1363 rows.push_back(row);
1364 SingleHeight(bv, par, p, asc, desc);
1365 rows[rows.size() - 1].asc = asc;
1366 rows[rows.size() - 1].desc = desc;
1367 row.pos = nwp = p + 1;
1368 rows.push_back(row);
1369 oasc = odesc = width = lastWordWidth = 0;
1370 is_first_word_in_row = true;
1371 wordAscent = wordDescent = 0;
1373 } else if (par->IsSeparator(p)) {
1374 if (width >= maxWidth) {
1375 if (is_first_word_in_row) {
1376 rows[rows.size()-1].asc = wordAscent;
1377 rows[rows.size()-1].desc = wordDescent;
1379 rows.push_back(row);
1380 oasc = odesc = width = 0;
1382 rows[rows.size()-1].asc = oasc;
1383 rows[rows.size()-1].desc = odesc;
1385 rows.push_back(row);
1387 odesc = wordDescent;
1388 if (insetWidth < owidth)
1389 insetWidth = owidth;
1390 width = lastWordWidth;
1392 wordAscent = wordDescent = lastWordWidth = 0;
1397 if (oasc < wordAscent)
1399 if (odesc < wordDescent)
1400 odesc = wordDescent;
1401 wordAscent = wordDescent = lastWordWidth = 0;
1403 is_first_word_in_row = false;
1406 // if we have some data in the paragraph we have ascent/descent
1408 if (width >= maxWidth) {
1410 rows[rows.size()-1].asc = oasc;
1411 rows[rows.size()-1].desc = odesc;
1412 // assign and allocate lower row
1414 rows.push_back(row);
1415 rows[rows.size()-1].asc = wordAscent;
1416 rows[rows.size()-1].desc = wordDescent;
1417 if (insetWidth < owidth)
1418 insetWidth = owidth;
1420 if (insetWidth < width)
1423 // assign last row data
1424 if (oasc < wordAscent)
1426 if (odesc < wordDescent)
1427 odesc = wordDescent;
1428 rows[rows.size()-1].asc = oasc;
1429 rows[rows.size()-1].desc = odesc;
1432 // alocate a dummy row for the endpos
1433 row.pos = par->Last();
1434 rows.push_back(row);
1435 // calculate maxAscent/Descent
1436 maxAscent = rows[0].asc;
1437 maxDescent = rows[0].desc;
1438 for (unsigned int i=1; i<rows.size()-1; ++i) {
1439 maxDescent += rows[i].asc + rows[i].desc + interline_space;
1441 if (the_locking_inset) {
1442 computeBaselines(top_baseline);
1450 void InsetText::computeBaselines(int baseline) const
1452 rows[0].baseline = baseline;
1453 for (unsigned int i=1; i<rows.size()-1; i++) {
1454 rows[i].baseline = rows[i-1].baseline + rows[i-1].desc +
1455 rows[i].asc + interline_space;
1459 void InsetText::init(BufferView * bv)
1463 computeTextRows(bv);