2 /* This file is part of
3 * ======================================================
5 * LyX, The Document Processor
7 * Copyright 1998-2000 The LyX Team.
9 * ======================================================
20 #pragma implementation
23 #include "insettext.h"
24 #include "lyxparagraph.h"
28 #include "commandtags.h"
31 #include "BufferView.h"
33 #include "LaTeXFeatures.h"
35 #include "lyx_gui_misc.h"
37 #include "lyxcursor.h"
38 #include "CutAndPaste.h"
40 #include "minibuffer.h"
43 #include "support/textutils.h"
44 #include "support/LAssert.h"
52 extern unsigned char getCurrentTextClass(Buffer *);
53 extern LyXTextClass::size_type current_layout;
56 InsetText::InsetText(Buffer * buf)
58 par = new LyXParagraph();
63 InsetText::InsetText(InsetText const & ins, Buffer * buf)
67 autoBreakRows = ins.autoBreakRows;
71 void InsetText::init(Buffer * buf, InsetText const * ins)
73 the_locking_inset = 0;
75 cursor_visible = false;
80 maxAscent = maxDescent = insetWidth = 0;
81 drawTextXOffset = drawTextYOffset = 0;
82 autoBreakRows = drawLockedFrame = false;
85 SetParagraphData(ins->par);
86 autoBreakRows = ins->autoBreakRows;
87 drawLockedFrame = ins->drawLockedFrame;
89 par->SetInsetOwner(this);
92 selection_start_cursor = selection_end_cursor = cursor;
93 frame_color = LColor::insetframe;
98 InsetText::~InsetText()
104 Inset * InsetText::Clone() const
106 InsetText * t = new InsetText(*this, buffer);
111 void InsetText::Write(ostream & os) const
114 WriteParagraphData(os);
118 void InsetText::WriteParagraphData(ostream & os) const
120 par->writeFile(os, buffer->params, 0, 0);
124 void InsetText::Read(LyXLex & lex)
126 string token, tmptok;
128 LyXParagraph * return_par = 0;
129 char depth = 0; // signed or unsigned?
130 LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
131 LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
132 LyXFont font(LyXFont::ALL_INHERIT);
135 par = new LyXParagraph;
136 par->SetInsetOwner(this);
140 token = lex.GetString();
143 if (token == "\\end_inset")
145 if (buffer->parseSingleLyXformat2Token(lex, par, return_par,
149 // the_end read this should NEVER happen
150 lex.printError("\\the_end read in inset! Error in document!");
154 if (token != "\\end_inset") {
155 lex.printError("Missing \\end_inset at this point. "
162 int InsetText::ascent(Painter & pain, LyXFont const & font) const
165 computeTextRows(pain);
170 return maxAscent + 2;
171 return lyxfont::maxAscent(font);
175 int InsetText::descent(Painter & pain, LyXFont const & font) const
178 computeTextRows(pain);
183 return maxDescent + 2;
184 return lyxfont::maxDescent(font);
188 int InsetText::width(Painter & pain, LyXFont const &) const
191 computeTextRows(pain);
199 void InsetText::draw(Painter & pain, LyXFont const & f,
200 int baseline, float & x) const
203 UpdatableInset::draw(pain, f, baseline, x);
205 if (init_inset || (baseline != top_baseline) || (top_x != int(x))) {
206 top_baseline = baseline;
207 if (init_inset || (top_x != int(x))) {
209 computeTextRows(pain);
212 computeBaselines(baseline);
214 if (the_locking_inset && (cursor.pos == inset_pos)) {
216 inset_x = cursor.x - top_x + drawTextXOffset;
217 inset_y = cursor.y + drawTextYOffset;
219 if (drawLockedFrame && locked) {
220 pain.rectangle(int(x), baseline - ascent(pain, f), insetWidth,
221 ascent(pain,f) + descent(pain, f), frame_color);
223 x += TEXT_TO_INSET_OFFSET; // place for border
224 for(RowList::size_type r = 0; r < rows.size() - 1; ++r) {
225 drawRowSelection(pain, rows[r].pos, rows[r + 1].pos, r,
226 rows[r].baseline, x);
227 drawRowText(pain, rows[r].pos, rows[r + 1].pos, rows[r].baseline, x);
229 x += insetWidth - TEXT_TO_INSET_OFFSET;
233 void InsetText::drawRowSelection(Painter & pain, int startpos, int endpos,
234 int row, int baseline, float x) const
240 if (selection_start_cursor.pos > selection_end_cursor.pos) {
241 s_start = selection_end_cursor.pos;
242 s_end = selection_start_cursor.pos;
244 s_start = selection_start_cursor.pos;
245 s_end = selection_end_cursor.pos;
247 if ((s_start > endpos) || (s_end < startpos))
251 int ssel_x = esel_x = int(x);
254 for(; p < endpos; ++p) {
257 if ((p >= s_start) && (p <= s_end))
259 char ch = par->GetChar(p);
260 font = GetDrawFont(par,p);
261 if (IsFloatChar(ch)) {
263 } else if (ch == LyXParagraph::META_INSET) {
264 Inset const * tmpinset = par->GetInset(p);
265 x += tmpinset->width(pain, font);
267 x += lyxfont::width(ch, font);
272 if ((p >= s_start) && (p <= s_end))
274 if (ssel_x < esel_x) {
275 pain.fillRectangle(int(ssel_x), baseline-rows[row].asc,
276 int(esel_x - ssel_x),
277 rows[row].asc + rows[row].desc,
283 void InsetText::drawRowText(Painter & pain, int startpos, int endpos,
284 int baseline, float x) const
286 Assert(endpos <= par->Last());
288 for(int p = startpos; p < endpos; ++p) {
289 char ch = par->GetChar(p);
290 LyXFont font = GetDrawFont(par,p);
291 if (IsFloatChar(ch)) {
293 } else if (par->IsNewline(p)) {
294 // Draw end-of-line marker
295 int wid = lyxfont::width('n', font);
296 int asc = lyxfont::maxAscent(font);
300 xp[0] = int(x + wid * 0.375);
301 yp[0] = int(y - 0.875 * asc * 0.75);
304 yp[1] = int(y - 0.500 * asc * 0.75);
306 xp[2] = int(x + wid * 0.375);
307 yp[2] = int(y - 0.125 * asc * 0.75);
309 pain.lines(xp, yp, 3, LColor::eolmarker);
312 yp[0] = int(y - 0.500 * asc * 0.75);
314 xp[1] = int(x + wid);
315 yp[1] = int(y - 0.500 * asc * 0.75);
317 xp[2] = int(x + wid);
318 yp[2] = int(y - asc * 0.75);
320 pain.lines(xp, yp, 3, LColor::eolmarker);
322 } else if (ch == LyXParagraph::META_INSET) {
323 Inset * tmpinset = par->GetInset(p);
325 tmpinset->draw(pain, font, baseline, x);
327 pain.text(int(x), baseline, ch, font);
328 x += lyxfont::width(ch, font);
334 char const * InsetText::EditMessage() const
336 return _("Opened Text Inset");
340 void InsetText::Edit(BufferView * bv, int x, int y, unsigned int button)
342 par->SetInsetOwner(this);
343 UpdatableInset::Edit(bv, x, y, button);
345 if (!bv->lockInset(this)) {
346 lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
350 the_locking_inset = 0;
351 inset_pos = inset_x = inset_y = 0;
352 setPos(bv->painter(), x, y);
353 checkAndActivateInset(bv, x, y, button);
354 selection_start_cursor = selection_end_cursor = cursor;
355 current_font = real_current_font = GetFont(par, cursor.pos);
356 bv->text->FinishUndo();
357 UpdateLocal(bv, true);
361 void InsetText::InsetUnlock(BufferView * bv)
363 if (the_locking_inset) {
364 the_locking_inset->InsetUnlock(bv);
365 the_locking_inset = 0;
368 lyxerr[Debug::INSETS] << "InsetText::InsetUnlock(" << this <<
370 selection_start_cursor = selection_end_cursor = cursor;
371 no_selection = false;
373 UpdateLocal(bv, true);
377 bool InsetText::LockInsetInInset(BufferView * bv, UpdatableInset * inset)
379 lyxerr[Debug::INSETS] << "InsetText::LockInsetInInset(" << inset << "): ";
382 if (inset == par->GetInset(cursor.pos)) {
383 lyxerr[Debug::INSETS] << "OK" << endl;
384 the_locking_inset = inset;
385 resetPos(bv->painter());
386 inset_x = cursor.x - top_x + drawTextXOffset;
387 inset_y = cursor.y + drawTextYOffset;
388 inset_pos = cursor.pos;
390 } else if (the_locking_inset && (the_locking_inset == inset)) {
391 if (cursor.pos == inset_pos) {
392 lyxerr[Debug::INSETS] << "OK" << endl;
393 resetPos(bv->painter());
394 inset_x = cursor.x - top_x + drawTextXOffset;
395 inset_y = cursor.y + drawTextYOffset;
397 lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
399 } else if (the_locking_inset) {
400 lyxerr[Debug::INSETS] << "MAYBE" << endl;
401 return the_locking_inset->LockInsetInInset(bv, inset);
403 lyxerr[Debug::INSETS] << "NOT OK" << endl;
408 bool InsetText::UnlockInsetInInset(BufferView * bv, UpdatableInset * inset,
411 if (!the_locking_inset)
413 if (the_locking_inset == inset) {
414 the_locking_inset->InsetUnlock(bv);
415 the_locking_inset = 0;
417 moveRight(bv, false);
420 return the_locking_inset->UnlockInsetInInset(bv, inset, lr);
424 bool InsetText::UpdateInsetInInset(BufferView * bv, Inset * inset)
426 if (!the_locking_inset)
428 if (the_locking_inset != inset)
429 return the_locking_inset->UpdateInsetInInset(bv, inset);
430 lyxerr[Debug::INSETS] << "InsetText::UpdateInsetInInset(" << inset <<
432 UpdateLocal(bv, true);
433 if (cursor.pos == inset_pos) {
434 inset_x = cursor.x - top_x + drawTextXOffset;
435 inset_y = cursor.y + drawTextYOffset;
441 void InsetText::InsetButtonPress(BufferView * bv, int x, int y, int button)
443 if (hasSelection()) {
444 selection_start_cursor = selection_end_cursor = cursor;
445 UpdateLocal(bv, false);
447 no_selection = false;
448 setPos(bv->painter(), x, y);
450 if (the_locking_inset) {
453 if (par->GetChar(cursor.pos) == LyXParagraph::META_INSET)
454 inset = static_cast<UpdatableInset*>(par->GetInset(cursor.pos));
455 if (the_locking_inset == inset) {
456 the_locking_inset->InsetButtonPress(bv,x-inset_x,y-inset_y,button);
459 // otherwise unlock the_locking_inset and lock the new inset
460 the_locking_inset->InsetUnlock(bv);
461 inset_x = cursor.x - top_x + drawTextXOffset;
462 inset_y = cursor.y + drawTextYOffset;
463 inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button);
464 inset->Edit(bv, x - inset_x, y - inset_y, button);
465 UpdateLocal(bv, true);
468 // otherwise only unlock the_locking_inset
469 the_locking_inset->InsetUnlock(bv);
470 the_locking_inset = 0;
472 if (bv->the_locking_inset) {
473 if ((par->GetChar(cursor.pos) == LyXParagraph::META_INSET) &&
474 par->GetInset(cursor.pos) &&
475 (par->GetInset(cursor.pos)->Editable() == Inset::HIGHLY_EDITABLE)) {
476 UpdatableInset *inset =
477 static_cast<UpdatableInset*>(par->GetInset(cursor.pos));
478 inset_x = cursor.x - top_x + drawTextXOffset;
479 inset_y = cursor.y + drawTextYOffset;
480 inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button);
481 inset->Edit(bv, x-inset_x, y-inset_y, 0);
482 UpdateLocal(bv, true);
485 selection_start_cursor = selection_end_cursor = cursor;
489 void InsetText::InsetButtonRelease(BufferView * bv, int x, int y, int button)
491 UpdatableInset * inset = 0;
493 if (the_locking_inset) {
494 the_locking_inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
496 if (par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
497 inset = static_cast<UpdatableInset*>(par->GetInset(cursor.pos));
498 if (inset->Editable()==Inset::HIGHLY_EDITABLE) {
499 inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
501 inset_x = cursor.x - top_x + drawTextXOffset;
502 inset_y = cursor.y + drawTextYOffset;
503 inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
504 inset->Edit(bv, x-inset_x, y-inset_y, button);
508 no_selection = false;
512 void InsetText::InsetMotionNotify(BufferView * bv, int x, int y, int state)
514 if (the_locking_inset) {
515 the_locking_inset->InsetMotionNotify(bv, x - inset_x,
520 LyXCursor old = selection_end_cursor;
522 setPos(bv->painter(), x, y);
523 selection_end_cursor = cursor;
524 if (old != selection_end_cursor)
525 UpdateLocal(bv, false);
528 no_selection = false;
532 void InsetText::InsetKeyPress(XKeyEvent * xke)
534 if (the_locking_inset) {
535 the_locking_inset->InsetKeyPress(xke);
541 UpdatableInset::RESULT
542 InsetText::LocalDispatch(BufferView * bv,
543 int action, string const & arg)
545 no_selection = false;
546 UpdatableInset::RESULT
547 result= UpdatableInset::LocalDispatch(bv, action, arg);
548 if (result != UNDISPATCHED) {
549 resetPos(bv->painter());
554 if ((action < 0) && arg.empty())
557 if ((action != LFUN_DOWN) && (action != LFUN_UP) &&
558 (action != LFUN_DOWNSEL) && (action != LFUN_UPSEL))
560 if (the_locking_inset) {
561 result = the_locking_inset->LocalDispatch(bv, action, arg);
562 if (result == DISPATCHED_NOUPDATE)
564 else if (result == DISPATCHED) {
565 the_locking_inset->ToggleInsetCursor(bv);
566 UpdateLocal(bv, false);
567 the_locking_inset->ToggleInsetCursor(bv);
569 } else if (result == FINISHED) {
573 cursor.pos = inset_pos + 1;
574 resetPos(bv->painter());
580 the_locking_inset = 0;
588 bv->text->SetUndo(Undo::INSERT,
589 bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
590 bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
592 cursor = selection_start_cursor;
593 par->InsertChar(cursor.pos,arg[0]);
594 SetCharFont(cursor.pos,current_font);
596 selection_start_cursor = selection_end_cursor = cursor;
597 UpdateLocal(bv, true);
599 // --- Cursor Movements ---------------------------------------------
601 bv->text->FinishUndo();
602 moveRight(bv, false);
603 selection_end_cursor = cursor;
604 UpdateLocal(bv, false);
607 bv->text->FinishUndo();
608 result = moveRight(bv);
609 if (hasSelection()) {
610 selection_start_cursor = selection_end_cursor = cursor;
611 UpdateLocal(bv, false);
613 selection_start_cursor = selection_end_cursor = cursor;
617 bv->text->FinishUndo();
619 selection_end_cursor = cursor;
620 UpdateLocal(bv, false);
623 bv->text->FinishUndo();
624 result= moveLeft(bv);
625 if (hasSelection()) {
626 selection_start_cursor = selection_end_cursor = cursor;
627 UpdateLocal(bv, false);
629 selection_start_cursor = selection_end_cursor = cursor;
633 bv->text->FinishUndo();
635 selection_end_cursor = cursor;
636 UpdateLocal(bv, false);
639 bv->text->FinishUndo();
640 result = moveDown(bv);
641 if (hasSelection()) {
642 selection_start_cursor = selection_end_cursor = cursor;
643 UpdateLocal(bv, false);
645 selection_start_cursor = selection_end_cursor = cursor;
649 bv->text->FinishUndo();
651 selection_end_cursor = cursor;
652 UpdateLocal(bv, false);
655 bv->text->FinishUndo();
657 if (hasSelection()) {
658 selection_start_cursor = selection_end_cursor = cursor;
659 UpdateLocal(bv, false);
661 selection_start_cursor = selection_end_cursor = cursor;
666 if (hasSelection()) {
667 selection_start_cursor = selection_end_cursor = cursor;
668 UpdateLocal(bv, false);
675 bv->text->SetUndo(Undo::DELETE,
676 bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
677 bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
679 if (hasSelection()) {
680 LyXParagraph::size_type i = selection_start_cursor.pos;
681 for (; i < selection_end_cursor.pos; ++i) {
682 par->Erase(selection_start_cursor.pos);
686 if (ret) { // we need update
687 selection_start_cursor = selection_end_cursor = cursor;
688 UpdateLocal(bv, true);
689 } else if (hasSelection()) {
690 selection_start_cursor = selection_end_cursor = cursor;
691 UpdateLocal(bv, false);
694 resetPos(bv->painter());
697 bv->text->SetUndo(Undo::DELETE,
698 bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
699 bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
701 if (cutSelection()) {
703 cursor = selection_end_cursor = selection_start_cursor;
704 UpdateLocal(bv, true);
705 } else if (hasSelection()) {
706 selection_start_cursor = selection_end_cursor = cursor;
707 UpdateLocal(bv, false);
709 resetPos(bv->painter());
712 bv->text->FinishUndo();
713 if (copySelection()) {
715 selection_start_cursor = selection_end_cursor = cursor;
716 UpdateLocal(bv, true);
717 } else if (hasSelection()) {
718 selection_start_cursor = selection_end_cursor = cursor;
719 UpdateLocal(bv, false);
724 bv->text->SetUndo(Undo::INSERT,
725 bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
726 bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
727 if (pasteSelection()) {
728 selection_start_cursor = selection_end_cursor = cursor;
729 UpdateLocal(bv, true);
732 resetPos(bv->painter());
735 bv->text->FinishUndo();
736 for(; cursor.pos > rows[actrow].pos; --cursor.pos)
737 cursor.x -= SingleWidth(bv->painter(), par, cursor.pos);
738 cursor.x -= SingleWidth(bv->painter(), par, cursor.pos);
739 if (hasSelection()) {
740 selection_start_cursor = selection_end_cursor = cursor;
741 UpdateLocal(bv, false);
743 selection_start_cursor = selection_end_cursor = cursor;
745 resetPos(bv->painter());
749 bv->text->FinishUndo();
750 int checkpos = (int)rows[actrow + 1].pos;
751 if ((actrow + 2) < (int)rows.size())
753 for(; cursor.pos < checkpos; ++cursor.pos)
754 cursor.x += SingleWidth(bv->painter(), par, cursor.pos);
755 if (hasSelection()) {
756 selection_start_cursor = selection_end_cursor = cursor;
757 UpdateLocal(bv, false);
759 selection_start_cursor = selection_end_cursor = cursor;
762 resetPos(bv->painter());
764 case LFUN_BREAKPARAGRAPH:
768 bv->text->SetUndo(Undo::INSERT,
769 bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
770 bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
771 par->InsertChar(cursor.pos,LyXParagraph::META_NEWLINE);
772 SetCharFont(cursor.pos,current_font);
773 UpdateLocal(bv, true);
775 selection_start_cursor = selection_end_cursor = cursor;
776 resetPos(bv->painter());
780 // Derive layout number from given argument (string)
781 // and current buffer's textclass (number). */
782 LyXTextClassList::ClassList::size_type tclass =
783 buffer->params.textclass;
784 std::pair <bool, LyXTextClass::size_type> layout =
785 textclasslist.NumberOfLayout(tclass, arg);
787 // If the entry is obsolete, use the new one instead.
789 string obs = textclasslist.Style(tclass,layout.second).
792 layout = textclasslist.NumberOfLayout(tclass, obs);
795 // see if we found the layout number:
797 string msg = string(N_("Layout ")) + arg + N_(" not known");
799 bv->owner()->getMiniBuffer()->Set(msg);
803 if (current_layout != layout.second) {
804 bv->text->SetLayout(cursor, selection_start_cursor,
805 selection_end_cursor, layout.second);
806 bv->owner()->getToolbar()->combox->select(cursor.par->GetLayout()+1);
807 UpdateLocal(bv, true);
812 result = UNDISPATCHED;
815 if (result != FINISHED) {
818 bv->unlockInset(this);
823 int InsetText::Latex(ostream & os, bool /*fragile*/, bool /*fp*/) const
826 buffer->latexParagraphs(os, par, 0, texrow);
827 return texrow.rows();
831 void InsetText::Validate(LaTeXFeatures & features) const
833 par->validate(features);
837 // Returns the width of a character at a certain spot
838 int InsetText::SingleWidth(Painter & pain, LyXParagraph * p, int pos) const
840 LyXFont font = GetDrawFont(p, pos);
841 char c = p->GetChar(pos);
843 if (IsPrintable(c)) {
844 return lyxfont::width(c, font);
845 } else if (c == LyXParagraph::META_INSET) {
846 Inset const * tmpinset = p->GetInset(pos);
848 return tmpinset->width(pain, font);
851 } else if (IsSeparatorChar(c))
853 else if (IsNewlineChar(c))
855 return lyxfont::width(c, font);
859 // Returns the width of a character at a certain spot
860 void InsetText::SingleHeight(Painter & pain, LyXParagraph * p,int pos,
861 int & asc, int & desc) const
863 LyXFont font = GetDrawFont(p, pos);
864 char c = p->GetChar(pos);
867 if (c == LyXParagraph::META_INSET) {
868 Inset const * tmpinset=p->GetInset(pos);
870 asc = tmpinset->ascent(pain, font);
871 desc = tmpinset->descent(pain, font);
874 asc = lyxfont::maxAscent(font);
875 desc = lyxfont::maxDescent(font);
881 // Gets the fully instantiated font at a given position in a paragraph
882 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
883 // The difference is that this one is used for displaying, and thus we
884 // are allowed to make cosmetic improvements. For instance make footnotes
886 // If position is -1, we get the layout font of the paragraph.
887 // If position is -2, we get the font of the manual label of the paragraph.
888 LyXFont InsetText::GetFont(LyXParagraph * p, int pos) const
890 char par_depth = p->GetDepth();
892 LyXLayout const & layout =
893 textclasslist.Style(buffer->params.textclass, p->GetLayout());
895 // We specialize the 95% common case:
896 if (p->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
899 if (layout.labeltype == LABEL_MANUAL
900 && pos < BeginningOfMainBody(p)) {
902 return p->GetFontSettings(pos).realize(layout.reslabelfont);
904 return p->GetFontSettings(pos).realize(layout.resfont);
907 // process layoutfont for pos == -1 and labelfont for pos < -1
909 return layout.resfont;
911 return layout.reslabelfont;
914 // The uncommon case need not be optimized as much
916 LyXFont layoutfont, tmpfont;
920 if (pos < BeginningOfMainBody(p)) {
922 layoutfont = layout.labelfont;
925 layoutfont = layout.font;
927 tmpfont = p->GetFontSettings(pos);
928 tmpfont.realize(layoutfont);
931 // process layoutfont for pos == -1 and labelfont for pos < -1
933 tmpfont = layout.font;
935 tmpfont = layout.labelfont;
938 // Resolve against environment font information
939 //if (par->GetDepth()){ // already in while condition
940 while (p && par_depth && !tmpfont.resolved()) {
941 p = p->DepthHook(par_depth - 1);
943 tmpfont.realize(textclasslist.Style(buffer->params.textclass,
944 p->GetLayout()).font);
945 par_depth = p->GetDepth();
948 tmpfont.realize((textclasslist.TextClass(buffer->params.textclass).
954 // the font for drawing may be different from the real font
955 LyXFont InsetText::GetDrawFont(LyXParagraph * p, int pos) const
957 return GetFont(p, pos);
961 int InsetText::BeginningOfMainBody(LyXParagraph * p) const
963 if (textclasslist.Style(buffer->params.textclass,
964 p->GetLayout()).labeltype != LABEL_MANUAL)
967 return p->BeginningOfMainBody();
971 void InsetText::GetCursorPos(int & x, int & y) const
978 int InsetText::InsetInInsetY()
980 if (!the_locking_inset)
983 return (inset_y + the_locking_inset->InsetInInsetY());
987 void InsetText::ToggleInsetCursor(BufferView * bv)
989 if (the_locking_inset) {
990 the_locking_inset->ToggleInsetCursor(bv);
994 LyXFont font = GetDrawFont(par, cursor.pos);
996 int asc = lyxfont::maxAscent(font);
997 int desc = lyxfont::maxDescent(font);
1000 bv->hideLockedInsetCursor();
1002 bv->showLockedInsetCursor(cursor.x, cursor.y, asc, desc);
1003 cursor_visible = !cursor_visible;
1007 void InsetText::ShowInsetCursor(BufferView * bv)
1009 if (the_locking_inset) {
1010 the_locking_inset->ShowInsetCursor(bv);
1013 if (!cursor_visible) {
1014 LyXFont font = GetDrawFont(par, cursor.pos);
1016 int asc = lyxfont::maxAscent(font);
1017 int desc = lyxfont::maxDescent(font);
1018 bv->fitLockedInsetCursor(cursor.x, cursor.y, asc, desc);
1019 bv->showLockedInsetCursor(cursor.x, cursor.y, asc, desc);
1020 cursor_visible = true;
1025 void InsetText::HideInsetCursor(BufferView * bv)
1027 if (cursor_visible) {
1028 bv->hideLockedInsetCursor();
1029 cursor_visible = false;
1031 if (the_locking_inset)
1032 the_locking_inset->HideInsetCursor(bv);
1036 void InsetText::setPos(Painter & pain, int x, int y) const
1038 x -= drawTextXOffset;
1039 y -= drawTextYOffset;
1040 // search right X-pos x==0 -> top_x
1041 cursor.pos = actrow = 0;
1042 cursor.y = top_baseline;
1044 for(unsigned int i = 1;
1045 (long(cursor.y + rows[i - 1].desc) < y)
1046 && (i < rows.size() - 1); ++i) {
1047 cursor.y = rows[i].baseline;
1048 cursor.pos = rows[i].pos;
1051 cursor.y -= top_baseline;
1052 cursor.x = top_x + 2; // 2 = frame width
1056 int sw = swh = SingleWidth(pain, par,cursor.pos);
1057 if (par->GetChar(cursor.pos)!=LyXParagraph::META_INSET)
1059 int checkpos = rows[actrow + 1].pos;
1060 if ((actrow+2) < (int)rows.size())
1062 while ((cursor.pos < checkpos) && ((cursor.x + swh) < x)) {
1065 sw = swh = SingleWidth(pain, par,cursor.pos);
1066 if (par->GetChar(cursor.pos)!=LyXParagraph::META_INSET)
1072 void InsetText::resetPos(Painter & pain) const
1079 int old_pos = cursor.pos;
1081 cursor.y = top_baseline;
1083 for(unsigned int i = 0;
1084 (i < (rows.size()-1)) && (rows[i].pos <= cursor.pos);
1086 cursor.y = rows[i].baseline;
1089 cursor.y -= top_baseline;
1090 setPos(pain, 0, cursor.y);
1091 cursor.x = top_x + 2; // 2 = frame width
1092 while(cursor.pos < old_pos) {
1093 cursor.x += SingleWidth(pain, par,cursor.pos);
1099 UpdatableInset::RESULT
1100 InsetText::moveRight(BufferView * bv, bool activate_inset)
1102 if (cursor.pos >= par->Last())
1104 if (activate_inset && checkAndActivateInset(bv)) {
1108 resetPos(bv->painter());
1109 real_current_font = current_font = GetFont(par, cursor.pos);
1110 return DISPATCHED_NOUPDATE;
1114 UpdatableInset::RESULT
1115 InsetText::moveLeft(BufferView * bv, bool activate_inset)
1117 if (cursor.pos <= 0)
1120 resetPos(bv->painter());
1122 if (checkAndActivateInset(bv, -1, -1))
1124 return DISPATCHED_NOUPDATE;
1128 UpdatableInset::RESULT
1129 InsetText::moveUp(BufferView * bv)
1133 cursor.y = rows[actrow - 1].baseline - top_baseline;
1134 if (cursor.x_fix < 0)
1135 cursor.x_fix = cursor.x;
1136 setPos(bv->painter(), cursor.x_fix-top_x+drawTextXOffset, cursor.y);
1137 return DISPATCHED_NOUPDATE;
1141 UpdatableInset::RESULT
1142 InsetText::moveDown(BufferView * bv)
1144 if (actrow >= int(rows.size() - 2))
1146 cursor.y = rows[actrow + 1].baseline - top_baseline;
1147 if (cursor.x_fix < 0)
1148 cursor.x_fix = cursor.x;
1149 setPos(bv->painter(), cursor.x_fix-top_x+drawTextXOffset, cursor.y);
1150 return DISPATCHED_NOUPDATE;
1154 bool InsetText::Delete()
1156 if ((par->GetChar(cursor.pos)==LyXParagraph::META_INSET) &&
1157 !par->GetInset(cursor.pos)->Deletable()) {
1160 par->Erase(cursor.pos);
1165 bool InsetText::InsertInset(BufferView * bv, Inset * inset)
1167 if (the_locking_inset) {
1168 if (the_locking_inset->InsertInsetAllowed(inset))
1169 return the_locking_inset->InsertInset(bv, inset);
1172 bv->text->SetUndo(Undo::INSERT,
1173 bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
1174 bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
1175 if (inset->Editable() == Inset::IS_EDITABLE) {
1176 UpdatableInset *i = (UpdatableInset *)inset;
1177 i->setOwner((UpdatableInset *)this);
1179 par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1180 par->InsertInset(cursor.pos, inset);
1181 if (hasSelection()) {
1182 selection_start_cursor = selection_end_cursor = cursor;
1184 selection_start_cursor = selection_end_cursor = cursor;
1186 UpdateLocal(bv, true);
1187 static_cast<UpdatableInset*>(inset)->Edit(bv, 0, 0, 0);
1192 UpdatableInset * InsetText::GetLockingInset()
1194 return the_locking_inset ? the_locking_inset->GetLockingInset() : this;
1198 UpdatableInset * InsetText::GetFirstLockingInsetOfType(Inset::Code c)
1202 if (the_locking_inset)
1203 return the_locking_inset->GetFirstLockingInsetOfType(c);
1208 void InsetText::SetFont(BufferView * bv, LyXFont const & font, bool toggleall)
1210 // if there is no selection just set the current_font
1211 if (!hasSelection()) {
1212 // Determine basis font
1214 if (cursor.pos < BeginningOfMainBody(par))
1215 layoutfont = GetFont(par, -2);
1217 layoutfont = GetFont(par, -1);
1219 // Update current font
1220 real_current_font.update(font, bv->buffer()->params.language_info,
1223 // Reduce to implicit settings
1224 current_font = real_current_font;
1225 current_font.reduce(layoutfont);
1226 // And resolve it completely
1227 real_current_font.realize(layoutfont);
1232 if (selection_start_cursor.pos > selection_end_cursor.pos) {
1233 s_start = selection_end_cursor.pos;
1234 s_end = selection_start_cursor.pos;
1236 s_start = selection_start_cursor.pos;
1237 s_end = selection_end_cursor.pos;
1240 while(s_start < s_end) {
1241 newfont = GetFont(par,s_start);
1242 newfont.update(font, bv->buffer()->params.language_info, toggleall);
1243 SetCharFont(s_start, newfont);
1246 UpdateLocal(bv, true);
1250 void InsetText::SetCharFont(int pos, LyXFont const & f)
1252 /* let the insets convert their font */
1255 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
1256 if (par->GetInset(pos))
1257 font = par->GetInset(pos)->ConvertFont(font);
1259 LyXLayout const & layout =
1260 textclasslist.Style(buffer->params.textclass,par->GetLayout());
1262 // Get concrete layout font to reduce against
1265 if (pos < BeginningOfMainBody(par))
1266 layoutfont = layout.labelfont;
1268 layoutfont = layout.font;
1271 layoutfont.realize((textclasslist.TextClass(buffer->params.textclass).
1274 // Now, reduce font against full layout font
1275 font.reduce(layoutfont);
1277 par->SetFont(pos, font);
1281 void InsetText::computeTextRows(Painter & pain) const
1295 int width = wordAscent = wordDescent = 0;
1296 insetWidth = maxAscent = maxDescent = 0;
1301 rows.push_back(row);
1302 if (!autoBreakRows) {
1303 for(p = 0; p < par->Last(); ++p) {
1304 insetWidth += SingleWidth(pain, par, p);
1305 SingleHeight(pain, par, p, asc, desc);
1306 maxAscent = max(maxAscent, asc);
1307 maxDescent = max(maxDescent, desc);
1309 insetWidth += (2 * TEXT_TO_INSET_OFFSET);
1310 rows[0].asc = maxAscent;
1311 rows[0].desc = maxDescent;
1312 // alocate a dummy row for the endpos
1313 row.pos = par->Last();
1314 rows.push_back(row);
1318 bool is_first_word_in_row = true;
1319 int cw, lastWordWidth = 0;
1320 int maxWidth = getMaxTextWidth(pain, this);
1321 // if we auto break rows than the insetwidth should be always the max
1322 // width as the display is stable it may get larger if we have a really
1323 // large word below and we draw it!!!
1324 insetWidth = maxWidth;
1326 for(p = 0; p < par->Last(); ++p) {
1327 if (par->IsNewline(p)) {
1328 rows.back().asc = wordAscent;
1329 rows.back().desc = wordDescent;
1331 rows.push_back(row);
1333 width = lastWordWidth = 0;
1334 oasc = odesc = wordAscent = wordDescent = 0;
1335 is_first_word_in_row = true;
1338 cw = SingleWidth(pain, par, p);
1340 if (par->GetChar(p) == LyXParagraph::META_INSET)
1341 inset = par->GetInset(p);
1342 if (inset && inset->display()) {
1343 inset->setOwner(const_cast<InsetText *>(this));
1346 if (!is_first_word_in_row || (p != nwp)) {
1347 oasc = max(oasc, wordAscent);
1348 odesc = max(odesc, wordDescent);
1349 rows.back().asc = oasc;
1350 rows.back().desc = odesc;
1352 rows.push_back(row);
1354 SingleHeight(pain, par, p, asc, desc);
1355 rows.back().asc = asc;
1356 rows.back().desc = desc;
1357 row.pos = nwp = p + 1;
1358 rows.push_back(row);
1359 width = lastWordWidth = 0;
1360 oasc = odesc = wordAscent = wordDescent = 0;
1361 is_first_word_in_row = true;
1364 SingleHeight(pain, par, p, asc, desc);
1366 lastWordWidth += cw;
1367 if (width > maxWidth) {
1368 if (is_first_word_in_row) {
1369 if (!(width-cw)) { // only this character in word
1370 rows.back().asc = asc;
1371 rows.back().desc = desc;
1373 rows.push_back(row);
1379 lastWordWidth = width = 0;
1381 rows.back().asc = wordAscent;
1382 rows.back().desc = wordDescent;
1384 rows.push_back(row);
1389 lastWordWidth = width = cw;
1393 rows.back().asc = oasc;
1394 rows.back().desc = odesc;
1396 rows.push_back(row);
1398 odesc = wordDescent;
1399 width = lastWordWidth;
1400 wordAscent = max(wordAscent, asc);
1401 wordDescent = max(wordDescent, desc);
1402 is_first_word_in_row = true;
1405 wordAscent = max(wordAscent, asc);
1406 wordDescent = max(wordDescent, desc);
1408 if (par->IsSeparator(p) || inset) {
1410 inset->setOwner(const_cast<InsetText *>(this));
1414 oasc = max(oasc, wordAscent);
1415 odesc = max(odesc, wordDescent);
1416 wordAscent = wordDescent = lastWordWidth = 0;
1418 is_first_word_in_row = false;
1421 // if we have some data in the paragraph we have ascent/descent
1423 // assign last row data
1424 rows.back().asc = max(oasc, wordAscent);
1425 rows.back().desc = max(odesc, wordDescent);
1427 insetWidth += (2 * TEXT_TO_INSET_OFFSET);
1428 // alocate a dummy row for the endpos
1429 row.pos = par->Last();
1430 rows.push_back(row);
1431 // calculate maxAscent/Descent
1432 maxAscent = rows[0].asc;
1433 maxDescent = rows[0].desc;
1434 for (RowList::size_type i = 1; i < rows.size() - 1; ++i) {
1435 maxDescent += rows[i].asc + rows[i].desc + interline_space;
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;
1450 void InsetText::UpdateLocal(BufferView * bv, bool flag)
1453 computeTextRows(bv->painter());
1454 computeBaselines(top_baseline);
1456 bv->updateInset(this, flag);
1458 resetPos(bv->painter());
1459 bv->owner()->getToolbar()->combox->select(cursor.par->GetLayout()+1);
1463 bool InsetText::cutSelection()
1465 if (!hasSelection())
1470 LyXParagraph * endpar = par;
1472 if (selection_start_cursor.pos > selection_end_cursor.pos) {
1473 start = selection_end_cursor.pos;
1474 end = selection_start_cursor.pos;
1476 start = selection_start_cursor.pos;
1477 end = selection_end_cursor.pos;
1480 return cap.cutSelection(par, &endpar, start, end,buffer->params.textclass);
1484 bool InsetText::copySelection()
1486 if (!hasSelection())
1492 if (selection_start_cursor.pos > selection_end_cursor.pos) {
1493 start = selection_end_cursor.pos;
1494 end = selection_start_cursor.pos;
1496 start = selection_start_cursor.pos;
1497 end = selection_end_cursor.pos;
1499 return cap.copySelection(par, par, start, end, buffer->params.textclass);
1503 bool InsetText::pasteSelection()
1507 if (cap.nrOfParagraphs() > 1) {
1508 WriteAlert(_("Impossible operation"),
1509 _("Cannot include more than one paragraph!"),
1513 LyXParagraph *endpar;
1514 LyXParagraph *actpar = par;
1516 return cap.pasteSelection(&actpar, &endpar, cursor.pos,
1517 buffer->params.textclass);
1521 bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y,
1524 if (par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
1525 UpdatableInset * inset =
1526 static_cast<UpdatableInset*>(par->GetInset(cursor.pos));
1527 LyXFont font = GetFont(par, cursor.pos);
1529 x = inset->width(bv->painter(), font);
1531 y = inset->descent(bv->painter(), font);
1532 inset_x = cursor.x - top_x + drawTextXOffset;
1533 inset_y = cursor.y + drawTextYOffset;
1534 inset->Edit(bv, x-inset_x, y-inset_y, button);
1535 if (!the_locking_inset)
1537 UpdateLocal(bv, true);
1544 int InsetText::getMaxTextWidth(Painter & pain, UpdatableInset const * inset) const
1546 // int w=getMaxWidth(pain, inset);
1548 return getMaxWidth(pain, inset) - 4; // 2+2 width of eventual border
1551 void InsetText::SetParagraphData(LyXParagraph *p)
1556 par->SetInsetOwner(this);
1560 void InsetText::SetAutoBreakRows(bool flag)
1562 if (flag != autoBreakRows) {
1563 autoBreakRows = flag;
1568 void InsetText::SetDrawLockedFrame(bool flag)
1570 if (flag != drawLockedFrame) {
1571 drawLockedFrame = flag;
1576 void InsetText::SetFrameColor(LColor::color col)
1578 if (frame_color != col) {