]> git.lyx.org Git - lyx.git/blob - src/insets/insettext.C
d06b57abcbea289530585557b584c1693f25551a
[lyx.git] / src / insets / insettext.C
1 // -*- C++ -*-
2 /* This file is part of
3  * ======================================================
4  * 
5  *           LyX, The Document Processor
6  *
7  *           Copyright 1998-2000 The LyX Team.
8  *
9  * ======================================================
10  */
11
12 #include <config.h>
13
14 #include <fstream>
15 #include <algorithm>
16
17 #include <cstdlib>
18
19 #ifdef __GNUG__
20 #pragma implementation
21 #endif
22
23 #include "insettext.h"
24 #include "lyxlex.h"
25 #include "debug.h"
26 #include "lyxfont.h"
27 #include "lyxlex.h"
28 #include "commandtags.h"
29 #include "buffer.h"
30 #include "LyXView.h"
31 #include "BufferView.h"
32 #include "support/textutils.h"
33 #include "layout.h"
34 #include "insetlatexaccent.h"
35 #include "insetquotes.h"
36 #include "mathed/formulamacro.h"
37 #include "figinset.h"
38 #include "insetinfo.h"
39 #include "insetinclude.h"
40 #include "insetbib.h"
41 #include "insetcommand.h"
42 #include "insetindex.h"
43 #include "insetlabel.h"
44 #include "insetref.h"
45 //#include "insettabular.h"
46 #include "insetert.h"
47 #include "insetspecialchar.h"
48 #include "LaTeXFeatures.h"
49 #include "Painter.h"
50 #include "lyx_gui_misc.h"
51 #include "support/LAssert.h"
52 #include "lyxtext.h"
53 #include "lyxcursor.h"
54 #include "CutAndPaste.h"
55 #include "font.h"
56
57 using std::ostream;
58 using std::ifstream;
59 using std::min;
60 using std::max;
61
62 extern unsigned char getCurrentTextClass(Buffer *);
63
64 InsetText::InsetText(Buffer * buf)
65 {
66     par = new LyXParagraph();
67     init(buf);
68 }
69
70
71 InsetText::InsetText(InsetText const & ins, Buffer * buf)
72 {
73     par = 0;
74     init(buf, &ins);
75     autoBreakRows = ins.autoBreakRows;
76 }
77
78 void InsetText::init(Buffer * buf, InsetText const * ins)
79 {
80     the_locking_inset = 0;
81     buffer = buf;
82     cursor_visible = false;
83     cursor.x_fix = -1;
84     selection_start = selection_end = 0;
85     interline_space = 1;
86     no_selection = false;
87     init_inset = true;
88     maxAscent = maxDescent = insetWidth = 0;
89     drawTextXOffset = drawTextYOffset = 0;
90     autoBreakRows = false;
91     xpos = 0.0;
92     if (ins) {
93         if (par)
94             delete par;
95         par = ins->par->Clone();
96         autoBreakRows = ins->autoBreakRows;
97     }
98     par->SetInsetOwner(this);
99     cursor.par = par;
100     cursor.pos = 0;
101 }
102
103
104 InsetText::~InsetText()
105 {
106     delete par;
107 }
108
109
110 Inset * InsetText::Clone() const
111 {
112     InsetText * t = new InsetText(*this, buffer);
113     return t;
114 }
115
116
117 void InsetText::Write(ostream & os) const
118 {
119     os << "Text\n";
120     WriteParagraphData(os);
121 }
122
123
124 void InsetText::WriteParagraphData(ostream & os) const
125 {
126     par->writeFile(os, buffer->params, 0, 0);
127 }
128
129
130 void InsetText::Read(LyXLex & lex)
131 {
132     string token, tmptok;
133     int pos = 0;
134     LyXParagraph * return_par = 0;
135     char depth = 0; // signed or unsigned?
136     LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
137     LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
138     LyXFont font(LyXFont::ALL_INHERIT);
139
140     delete par;
141     par = new LyXParagraph;
142     par->SetInsetOwner(this);
143     
144     while (lex.IsOK()) {
145         lex.nextToken();
146         token = lex.GetString();
147         if (token.empty())
148             continue;
149         if (token == "\\end_inset")
150             break;
151         if (buffer->parseSingleLyXformat2Token(lex, par, return_par,
152                                                token, pos, depth,
153                                                font, footnoteflag,
154                                                footnotekind)) {
155             // the_end read this should NEVER happen
156             lex.printError("\\the_end read in inset! Error in document!");
157             return;
158         }
159     }
160     if (token != "\\end_inset") {
161         lex.printError("Missing \\end_inset at this point. "
162                        "Read: `$$Token'");
163     }
164     init_inset = true;
165 }
166
167
168 int InsetText::ascent(Painter & pain, LyXFont const & font) const
169 {
170     if (init_inset) {
171         computeTextRows(pain, xpos);
172         resetPos(pain);
173         init_inset = false;
174     }
175     if (maxAscent)
176         return maxAscent;
177     return lyxfont::maxAscent(font);
178 }
179
180
181 int InsetText::descent(Painter & pain, LyXFont const & font) const
182 {
183     if (init_inset) {
184         computeTextRows(pain, xpos);
185         resetPos(pain);
186         init_inset = false;
187     }
188     if (maxDescent)
189         return maxDescent;
190     return lyxfont::maxDescent(font);
191 }
192
193
194 int InsetText::width(Painter & pain, LyXFont const &) const
195 {
196     if (init_inset) {
197         computeTextRows(pain, xpos);
198         resetPos(pain);
199         init_inset = false;
200     }
201     return insetWidth;
202 }
203
204
205 void InsetText::draw(Painter & pain, LyXFont const & f,
206                      int baseline, float & x) const
207 {
208     xpos = x;
209     UpdatableInset::draw(pain, f, baseline, x);
210     
211     top_x = int(x);
212     top_baseline = baseline;
213     computeTextRows(pain, x);
214     computeBaselines(baseline);
215     if (the_locking_inset && (cursor.pos == inset_pos)) {
216         resetPos(pain);
217         inset_x = cursor.x - top_x + drawTextXOffset;
218         inset_y = cursor.y + drawTextYOffset;
219     }
220     for(RowList::size_type r = 0; r < rows.size() - 1; ++r) {
221         drawRowSelection(pain, rows[r].pos, rows[r + 1].pos, r, 
222                          rows[r].baseline, x);
223         drawRowText(pain, rows[r].pos, rows[r + 1].pos, rows[r].baseline, x);
224     }
225     x += insetWidth;
226 }
227
228
229 void InsetText::drawRowSelection(Painter & pain, int startpos, int endpos,
230                                  int row, int baseline, float x) const
231 {
232     if (!hasSelection())
233         return;
234
235     int s_start, s_end;
236     if (selection_start > selection_end) {
237         s_start = selection_end;
238         s_end = selection_start;
239     } else {
240         s_start = selection_start;
241         s_end = selection_end;
242     }
243     if ((s_start > endpos) || (s_end < startpos))
244         return;
245     
246     int esel_x;
247     int ssel_x = esel_x = int(x);
248     LyXFont font;
249     int p = startpos;
250     for(; p < endpos; ++p) {
251         if (p == s_start)
252             ssel_x = int(x);
253         if ((p >= s_start) && (p <= s_end))
254             esel_x = int(x);
255         char ch = par->GetChar(p);
256         font = GetDrawFont(par,p);
257         if (IsFloatChar(ch)) {
258             // skip for now
259         } else if (ch == LyXParagraph::META_INSET) {
260             Inset const * tmpinset = par->GetInset(p);
261             x += tmpinset->width(pain, font);
262         } else {
263             x += lyxfont::width(ch, font);
264         }
265     }
266     if (p == s_start)
267         ssel_x = int(x);
268     if ((p >= s_start) && (p <= s_end))
269         esel_x = int(x);
270     if (ssel_x < esel_x) {
271         pain.fillRectangle(int(ssel_x), baseline-rows[row].asc,
272                            int(esel_x - ssel_x),
273                            rows[row].asc + rows[row].desc,
274                            LColor::selection);
275     }
276 }
277
278
279 void InsetText::drawRowText(Painter & pain, int startpos, int endpos,
280                             int baseline, float x) const
281 {
282     Assert(endpos <= par->Last());
283
284     for(int p = startpos; p < endpos; ++p) {
285         char ch = par->GetChar(p);
286         LyXFont font = GetDrawFont(par,p);
287         if (IsFloatChar(ch)) {
288             // skip for now
289         } else if (par->IsNewline(p)) {
290                 // Draw end-of-line marker
291                 int wid = lyxfont::width('n', font);
292                 int asc = lyxfont::maxAscent(font);
293                 int y = baseline;
294                 int xp[3], yp[3];
295                 
296                 xp[0] = int(x + wid * 0.375);
297                 yp[0] = int(y - 0.875 * asc * 0.75);
298                 
299                 xp[1] = int(x);
300                 yp[1] = int(y - 0.500 * asc * 0.75);
301                 
302                 xp[2] = int(x + wid * 0.375);
303                 yp[2] = int(y - 0.125 * asc * 0.75);
304                 
305                 pain.lines(xp, yp, 3, LColor::eolmarker);
306                 
307                 xp[0] = int(x);
308                 yp[0] = int(y - 0.500 * asc * 0.75);
309                 
310                 xp[1] = int(x + wid);
311                 yp[1] = int(y - 0.500 * asc * 0.75);
312                 
313                 xp[2] = int(x + wid);
314                 yp[2] = int(y - asc * 0.75);
315                         
316                 pain.lines(xp, yp, 3, LColor::eolmarker);
317                 x += wid;
318         } else if (ch == LyXParagraph::META_INSET) {
319             Inset * tmpinset = par->GetInset(p);
320             if (tmpinset) 
321                 tmpinset->draw(pain, font, baseline, x);
322         } else {
323             pain.text(int(x), baseline, ch, font);
324             x += lyxfont::width(ch, font);
325         }
326     }
327 }
328
329
330 char const * InsetText::EditMessage() const
331 {
332     return _("Opened Text Inset");
333 }
334
335
336 void InsetText::Edit(BufferView * bv, int x, int y, unsigned int button)
337 {
338     par->SetInsetOwner(this);
339     UpdatableInset::Edit(bv, x, y, button);
340
341     if (!bv->lockInset(this)) {
342         lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
343         return;
344     }
345     the_locking_inset = 0;
346     selection_start = selection_end = inset_pos = inset_x = inset_y = 0;
347 //    no_selection = true;
348     setPos(bv->painter(), x, y);
349     checkAndActivateInset(bv, x, y, button);
350     selection_start = selection_end = cursor.pos;
351     current_font = real_current_font = GetFont(par, cursor.pos);
352     bv->text->FinishUndo();
353     UpdateLocal(bv, true);
354 }
355
356
357 void InsetText::InsetUnlock(BufferView * bv)
358 {
359     if (the_locking_inset) {
360         the_locking_inset->InsetUnlock(bv);
361         the_locking_inset = 0;
362     }
363     lyxerr[Debug::INSETS] << "InsetText::InsetUnlock(" << this <<
364             ")" << endl;
365     if (hasSelection()) {
366         selection_start = selection_end = cursor.pos;
367         UpdateLocal(bv, false);
368     }
369     no_selection = false;
370 }
371
372 bool InsetText::LockInsetInInset(BufferView * bv, UpdatableInset * inset)
373 {
374     lyxerr[Debug::INSETS] << "InsetText::LockInsetInInset(" << inset << "): ";
375     if (!inset)
376         return false;
377     if (inset == par->GetInset(cursor.pos)) {
378         lyxerr[Debug::INSETS] << "OK" << endl;
379         the_locking_inset = inset;
380         resetPos(bv->painter());
381         inset_x = cursor.x - top_x + drawTextXOffset;
382         inset_y = cursor.y + drawTextYOffset;
383         inset_pos = cursor.pos;
384         return true;
385     } else if (the_locking_inset && (the_locking_inset == inset)) {
386         if (cursor.pos == inset_pos) {
387             lyxerr[Debug::INSETS] << "OK" << endl;
388             resetPos(bv->painter());
389             inset_x = cursor.x - top_x + drawTextXOffset;
390             inset_y = cursor.y + drawTextYOffset;
391         } else {
392             lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
393         }
394     } else if (the_locking_inset) {
395         lyxerr[Debug::INSETS] << "MAYBE" << endl;
396         return the_locking_inset->LockInsetInInset(bv, inset);
397     }
398     lyxerr[Debug::INSETS] << "NOT OK" << endl;
399     return false;
400 }
401
402 bool InsetText::UnlockInsetInInset(BufferView * bv, UpdatableInset * inset,
403                                    bool lr)
404 {
405     if (!the_locking_inset)
406         return false;
407     if (the_locking_inset == inset) {
408         the_locking_inset->InsetUnlock(bv);
409         the_locking_inset = 0;
410         if (lr)
411             moveRight(bv, false);
412         return true;
413     }
414     return the_locking_inset->UnlockInsetInInset(bv, inset, lr);
415 }
416
417
418 bool InsetText::UpdateInsetInInset(BufferView * bv, Inset * inset)
419 {
420     if (!the_locking_inset)
421         return false;
422     if (the_locking_inset != inset)
423         return the_locking_inset->UpdateInsetInInset(bv, inset);
424     lyxerr[Debug::INSETS] << "InsetText::UpdateInsetInInset(" << inset <<
425             ")" << endl;
426     UpdateLocal(bv, true);
427     if (cursor.pos == inset_pos) {
428         inset_x = cursor.x - top_x + drawTextXOffset;
429         inset_y = cursor.y + drawTextYOffset;
430     }
431     return true;
432 }
433
434
435 void InsetText::InsetButtonPress(BufferView * bv, int x, int y, int button)
436 {
437     if (hasSelection()) {
438         selection_start = selection_end = cursor.pos;
439         UpdateLocal(bv, false);
440     }
441     no_selection = false;
442     setPos(bv->painter(), x, y);
443     cursor.x_fix = -1;
444     if (the_locking_inset) {
445         UpdatableInset
446             *inset = 0;
447         if (par->GetChar(cursor.pos) == LyXParagraph::META_INSET)
448             inset = static_cast<UpdatableInset*>(par->GetInset(cursor.pos));
449         if (the_locking_inset == inset) {
450             the_locking_inset->InsetButtonPress(bv,x-inset_x,y-inset_y,button);
451             return;
452         } else if (inset) {
453             // otherwise unlock the_locking_inset and lock the new inset
454             the_locking_inset->InsetUnlock(bv);
455             inset_x = cursor.x - top_x + drawTextXOffset;
456             inset_y = cursor.y + drawTextYOffset;
457             inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button);
458             inset->Edit(bv, x - inset_x, y - inset_y, button);
459             UpdateLocal(bv, true);
460             return;
461         }
462         // otherwise only unlock the_locking_inset
463         the_locking_inset->InsetUnlock(bv);
464         the_locking_inset = 0;
465     }
466     if (bv->the_locking_inset) {
467         if ((par->GetChar(cursor.pos) == LyXParagraph::META_INSET) &&
468             par->GetInset(cursor.pos) &&
469             (par->GetInset(cursor.pos)->Editable() == Inset::HIGHLY_EDITABLE)) {
470             UpdatableInset *inset =
471                 static_cast<UpdatableInset*>(par->GetInset(cursor.pos));
472             inset_x = cursor.x - top_x + drawTextXOffset;
473             inset_y = cursor.y + drawTextYOffset;
474             inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button);
475             inset->Edit(bv, x-inset_x, y-inset_y, 0);
476             UpdateLocal(bv, true);
477         }
478     }
479     selection_start = selection_end = cursor.pos;
480 }
481
482
483 void InsetText::InsetButtonRelease(BufferView * bv, int x, int y, int button)
484 {
485     UpdatableInset * inset = 0;
486
487     if (the_locking_inset) {
488             the_locking_inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
489     } else {
490         if (par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
491             inset = static_cast<UpdatableInset*>(par->GetInset(cursor.pos));
492             if (inset->Editable()==Inset::HIGHLY_EDITABLE) {
493                 inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
494             } else {
495                 inset_x = cursor.x - top_x + drawTextXOffset;
496                 inset_y = cursor.y + drawTextYOffset;
497                 inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
498                 inset->Edit(bv, x-inset_x, y-inset_y, button);
499             }
500         }
501     }
502     no_selection = false;
503 }
504
505
506 void InsetText::InsetMotionNotify(BufferView * bv, int x, int y, int state)
507 {
508     if (the_locking_inset) {
509         the_locking_inset->InsetMotionNotify(bv, x - inset_x,
510                                              y - inset_y,state);
511         return;
512     }
513     if (!no_selection) {
514         int old = selection_end;
515         HideInsetCursor(bv);
516         setPos(bv->painter(), x, y);
517         selection_end = cursor.pos;
518         if (old != selection_end)
519             UpdateLocal(bv, false);
520         ShowInsetCursor(bv);
521     }
522     no_selection = false;
523 }
524
525
526 void InsetText::InsetKeyPress(XKeyEvent * xke)
527 {
528     if (the_locking_inset) {
529         the_locking_inset->InsetKeyPress(xke);
530         return;
531     }
532 }
533
534
535 UpdatableInset::RESULT
536 InsetText::LocalDispatch(BufferView * bv,
537                          int action, string const & arg)
538 {
539     no_selection = false;
540     UpdatableInset::RESULT
541         result= UpdatableInset::LocalDispatch(bv, action, arg);
542     if (result != UNDISPATCHED) {
543         resetPos(bv->painter());
544         return DISPATCHED;
545     }
546
547     result=DISPATCHED;
548     if ((action < 0) && arg.empty())
549         return FINISHED;
550
551     if ((action != LFUN_DOWN) && (action != LFUN_UP) &&
552         (action != LFUN_DOWNSEL) && (action != LFUN_UPSEL))
553         cursor.x_fix = -1;
554     if (the_locking_inset) {
555         result = the_locking_inset->LocalDispatch(bv, action, arg);
556         if (result == DISPATCHED_NOUPDATE)
557             return result;
558         else if (result == DISPATCHED) {
559             the_locking_inset->ToggleInsetCursor(bv);
560             UpdateLocal(bv, false);
561             the_locking_inset->ToggleInsetCursor(bv);
562             return result;
563         } else if (result == FINISHED) {
564             switch(action) {
565             case -1:
566             case LFUN_RIGHT:
567                 cursor.pos = inset_pos + 1;
568                 resetPos(bv->painter());
569                 break;
570             case LFUN_DOWN:
571                 moveDown(bv);
572                 break;
573             }
574             the_locking_inset = 0;
575             return DISPATCHED;
576         }
577     }
578     HideInsetCursor(bv);
579     switch (action) {
580         // Normal chars
581     case -1:
582         bv->text->SetUndo(Undo::INSERT, 
583             bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
584             bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
585         cutSelection();
586         cursor.pos = selection_start;
587         par->InsertChar(cursor.pos,arg[0]);
588         SetCharFont(cursor.pos,current_font);
589         ++cursor.pos;
590         selection_start = selection_end = cursor.pos;
591         UpdateLocal(bv, true);
592         break;
593         // --- Cursor Movements ---------------------------------------------
594     case LFUN_RIGHTSEL:
595         bv->text->FinishUndo();
596         moveRight(bv, false);
597         selection_end = cursor.pos;
598         UpdateLocal(bv, false);
599         break;
600     case LFUN_RIGHT:
601         bv->text->FinishUndo();
602         result = moveRight(bv);
603         if (hasSelection()) {
604             selection_start = selection_end = cursor.pos;
605             UpdateLocal(bv, false);
606         } else {
607             selection_start = selection_end = cursor.pos;
608         }
609         break;
610     case LFUN_LEFTSEL:
611         bv->text->FinishUndo();
612         moveLeft(bv, false);
613         selection_end = cursor.pos;
614         UpdateLocal(bv, false);
615         break;
616     case LFUN_LEFT:
617         bv->text->FinishUndo();
618         result= moveLeft(bv);
619         if (hasSelection()) {
620                 selection_start = selection_end = cursor.pos;
621                 UpdateLocal(bv, false);
622         } else {
623                 selection_start = selection_end = cursor.pos;
624         }
625         break;
626     case LFUN_DOWNSEL:
627         bv->text->FinishUndo();
628         moveDown(bv);
629         selection_end = cursor.pos;
630         UpdateLocal(bv, false);
631         break;
632     case LFUN_DOWN:
633         bv->text->FinishUndo();
634         result = moveDown(bv);
635         if (hasSelection()) {
636             selection_start = selection_end = cursor.pos;
637             UpdateLocal(bv, false);
638         } else {
639             selection_start = selection_end = cursor.pos;
640         }
641         break;
642     case LFUN_UPSEL:
643         bv->text->FinishUndo();
644         moveUp(bv);
645         selection_end = cursor.pos;
646         UpdateLocal(bv, false);
647         break;
648     case LFUN_UP:
649         bv->text->FinishUndo();
650         result = moveUp(bv);
651         if (hasSelection()) {
652             selection_start = selection_end = cursor.pos;
653             UpdateLocal(bv, false);
654         } else {
655             selection_start = selection_end = cursor.pos;
656         }
657         break;
658     case LFUN_BACKSPACE:
659         if (!cursor.pos) { // || par->IsNewline(cursor.pos-1)) {
660             if (hasSelection()) {
661                 selection_start = selection_end = cursor.pos;
662                 UpdateLocal(bv, false);
663             }
664             break;
665         }
666         moveLeft(bv);
667     case LFUN_DELETE:
668     {
669         bv->text->SetUndo(Undo::DELETE, 
670             bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
671             bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
672         bool ret = true;
673         if (hasSelection()) {
674             LyXParagraph::size_type i = selection_start;
675             for (; i < selection_end; ++i) {
676                 par->Erase(selection_start);
677             }
678         } else
679             ret = Delete();
680         if (ret) { // we need update
681             selection_start = selection_end = cursor.pos;
682             UpdateLocal(bv, true);
683         } else if (hasSelection()) {
684             selection_start = selection_end = cursor.pos;
685             UpdateLocal(bv, false);
686         }
687     }
688     resetPos(bv->painter());
689     break;
690     case LFUN_CUT:
691         bv->text->SetUndo(Undo::DELETE, 
692           bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
693           bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
694
695         if (cutSelection()) {
696             // we need update
697             cursor.pos = selection_end = selection_start;
698             UpdateLocal(bv, true);
699         } else if (hasSelection()) {
700             selection_start = selection_end = cursor.pos;
701             UpdateLocal(bv, false);
702         }
703         resetPos(bv->painter());
704         break;
705     case LFUN_COPY:
706         bv->text->FinishUndo();
707         if (copySelection()) {
708             // we need update
709             selection_start = selection_end = cursor.pos;
710             UpdateLocal(bv, true);
711         } else if (hasSelection()) {
712             selection_start = selection_end = cursor.pos;
713             UpdateLocal(bv, false);
714         }
715         break;
716     case LFUN_PASTE:
717     {
718         bv->text->SetUndo(Undo::INSERT, 
719           bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
720           bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
721         if (pasteSelection()) {
722             selection_start = selection_end = cursor.pos;
723             UpdateLocal(bv, true);
724         }
725     }
726     resetPos(bv->painter());
727     break;
728     case LFUN_HOME:
729         bv->text->FinishUndo();
730         for(; cursor.pos > rows[actrow].pos; --cursor.pos)
731             cursor.x -= SingleWidth(bv->painter(), par, cursor.pos);
732         cursor.x -= SingleWidth(bv->painter(), par, cursor.pos);
733         if (hasSelection()) {
734             selection_start = selection_end = cursor.pos;
735             UpdateLocal(bv, false);
736         } else {
737             selection_start = selection_end = cursor.pos;
738         }
739         resetPos(bv->painter());
740         break;
741     case LFUN_END:
742     {
743         bv->text->FinishUndo();
744         int checkpos = (int)rows[actrow + 1].pos;
745         if ((actrow + 2) < (int)rows.size())
746             --checkpos;
747         for(; cursor.pos < checkpos; ++cursor.pos)
748             cursor.x += SingleWidth(bv->painter(), par, cursor.pos);
749         if (hasSelection()) {
750             selection_start = selection_end = cursor.pos;
751             UpdateLocal(bv, false);
752         } else {
753             selection_start = selection_end = cursor.pos;
754         }
755     }
756     resetPos(bv->painter());
757     break;
758     case LFUN_MATH_MODE:
759         InsertInset(bv, new InsetFormula);
760         return DISPATCHED;
761     case LFUN_INSET_ERT:
762         InsertInset(bv, new InsetERT(buffer));
763         return DISPATCHED;
764     case LFUN_BREAKPARAGRAPH:
765     case LFUN_BREAKLINE:
766         if (!autoBreakRows)
767             return DISPATCHED;
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);
774         ++cursor.pos;
775         selection_start = selection_end = cursor.pos;
776         resetPos(bv->painter());
777         break;
778     default:
779         result = UNDISPATCHED;
780         break;
781     }
782     if (result != FINISHED) {
783         ShowInsetCursor(bv);
784     } else
785         bv->unlockInset(this);
786     return result;
787 }
788
789
790 int InsetText::Latex(ostream & os, bool /*fragile*/, bool) const
791 {
792         TexRow texrow;
793         int ret = par->SimpleTeXOnePar(os, texrow);
794         return ret;
795 }
796
797
798 void InsetText::Validate(LaTeXFeatures & features) const
799 {
800     par->validate(features);
801 }
802
803
804 // Returns the width of a character at a certain spot
805 int InsetText::SingleWidth(Painter & pain, LyXParagraph * par, int pos) const
806 {
807     LyXFont font = GetDrawFont(par, pos);
808     char c = par->GetChar(pos);
809
810     if (IsPrintable(c)) {
811         return lyxfont::width(c, font);
812     } else if (c == LyXParagraph::META_INSET) {
813         Inset const * tmpinset = par->GetInset(pos);
814         if (tmpinset)
815             return tmpinset->width(pain, font);
816         else
817             return 0;
818     } else if (IsSeparatorChar(c))
819         c = ' ';
820     else if (IsNewlineChar(c))
821         c = 'n';
822     return lyxfont::width(c, font);
823 }
824
825
826 // Returns the width of a character at a certain spot
827 void InsetText::SingleHeight(Painter & pain, LyXParagraph * par,int pos,
828                              int & asc, int & desc) const
829 {
830     LyXFont font = GetDrawFont(par, pos);
831     char c = par->GetChar(pos);
832
833     asc = desc = 0;
834     if (c == LyXParagraph::META_INSET) {
835         Inset const * tmpinset=par->GetInset(pos);
836         if (tmpinset) {
837             asc = tmpinset->ascent(pain, font);
838             desc = tmpinset->descent(pain, font);
839         }
840     } else {
841         asc = lyxfont::maxAscent(font);
842         desc = lyxfont::maxDescent(font);
843     }
844     return;
845 }
846
847
848 // Gets the fully instantiated font at a given position in a paragraph
849 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
850 // The difference is that this one is used for displaying, and thus we
851 // are allowed to make cosmetic improvements. For instance make footnotes
852 // smaller. (Asger)
853 // If position is -1, we get the layout font of the paragraph.
854 // If position is -2, we get the font of the manual label of the paragraph.
855 LyXFont InsetText::GetFont(LyXParagraph * par, int pos) const
856 {
857     char par_depth = par->GetDepth();
858
859     LyXLayout const & layout =
860             textclasslist.Style(buffer->params.textclass, par->GetLayout());
861
862     // We specialize the 95% common case:
863     if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
864         if (pos >= 0) {
865             // 95% goes here
866             if (layout.labeltype == LABEL_MANUAL
867                 && pos < BeginningOfMainBody(par)) {
868                 // 1% goes here
869                 return par->GetFontSettings(pos).realize(layout.reslabelfont);
870             } else
871                 return par->GetFontSettings(pos).realize(layout.resfont);
872         } else {
873             // 5% goes here.
874             // process layoutfont for pos == -1 and labelfont for pos < -1
875             if (pos == -1)
876                 return layout.resfont;
877             else
878                 return layout.reslabelfont;
879         }
880     }
881     // The uncommon case need not be optimized as much
882
883     LyXFont layoutfont, tmpfont;
884
885     if (pos >= 0){
886         // 95% goes here
887         if (pos < BeginningOfMainBody(par)) {
888             // 1% goes here
889             layoutfont = layout.labelfont;
890         } else {
891             // 99% goes here
892             layoutfont = layout.font;
893         }
894         tmpfont = par->GetFontSettings(pos);
895         tmpfont.realize(layoutfont);
896     } else{
897         // 5% goes here.
898         // process layoutfont for pos == -1 and labelfont for pos < -1
899         if (pos == -1)
900             tmpfont = layout.font;
901         else
902             tmpfont = layout.labelfont;
903     }
904     
905     // Resolve against environment font information
906     //if (par->GetDepth()){ // already in while condition
907     while (par && par_depth && !tmpfont.resolved()) {
908         par = par->DepthHook(par_depth - 1);
909         if (par) {
910             tmpfont.realize(textclasslist.Style(buffer->params.textclass,
911                                                 par->GetLayout()).font);
912             par_depth = par->GetDepth();
913         }
914     }
915     tmpfont.realize((textclasslist.TextClass(buffer->params.textclass).
916                     defaultfont()));
917     return tmpfont;
918 }
919
920 // the font for drawing may be different from the real font
921 LyXFont InsetText::GetDrawFont(LyXParagraph * par, int pos) const
922 {
923     return GetFont(par, pos);
924 }
925
926 int InsetText::BeginningOfMainBody(LyXParagraph * par) const
927 {
928     if (textclasslist.Style(buffer->params.textclass,
929                        par->GetLayout()).labeltype != LABEL_MANUAL)
930         return 0;
931     else
932         return par->BeginningOfMainBody();
933 }
934
935
936 void InsetText::GetCursorPos(int & x, int & y) const
937 {
938     x = cursor.x;
939     y = cursor.y;
940 }
941
942
943 int InsetText::InsetInInsetY()
944 {
945     if (!the_locking_inset)
946         return 0;
947
948     return (inset_y + the_locking_inset->InsetInInsetY());
949 }
950
951
952 void InsetText::ToggleInsetCursor(BufferView * bv)
953 {
954     if (the_locking_inset) {
955         the_locking_inset->ToggleInsetCursor(bv);
956         return;
957     }
958
959     LyXFont font = GetDrawFont(par, cursor.pos);
960
961     int asc = lyxfont::maxAscent(font);
962     int desc = lyxfont::maxDescent(font);
963   
964     if (cursor_visible)
965         bv->hideLockedInsetCursor();
966     else
967         bv->showLockedInsetCursor(cursor.x, cursor.y, asc, desc);
968     cursor_visible = !cursor_visible;
969 }
970
971
972 void InsetText::ShowInsetCursor(BufferView * bv)
973 {
974     if (the_locking_inset) {
975         the_locking_inset->ShowInsetCursor(bv);
976         return;
977     }
978     if (!cursor_visible) {
979         LyXFont font = GetDrawFont(par, cursor.pos);
980         
981         int asc = lyxfont::maxAscent(font);
982         int desc = lyxfont::maxDescent(font);
983         bv->fitLockedInsetCursor(cursor.x, cursor.y, asc, desc);
984         bv->showLockedInsetCursor(cursor.x, cursor.y, asc, desc);
985         cursor_visible = true;
986     }
987 }
988
989
990 void InsetText::HideInsetCursor(BufferView * bv)
991 {
992     if (cursor_visible) {
993         bv->hideLockedInsetCursor();
994         cursor_visible = false;
995     }
996     if (the_locking_inset)
997         the_locking_inset->HideInsetCursor(bv);
998 }
999
1000
1001 void InsetText::setPos(Painter & pain, int x, int y) const
1002 {
1003     x -= drawTextXOffset;
1004     y -= drawTextYOffset;
1005     // search right X-pos x==0 -> top_x
1006     cursor.pos = actrow = 0;
1007     cursor.y = top_baseline;
1008     y += cursor.y;
1009     for(unsigned int i = 1;
1010         ((cursor.y + rows[i - 1].desc) < y) && (i < rows.size() - 1); ++i) {
1011         cursor.y = rows[i].baseline;
1012         cursor.pos = rows[i].pos;
1013         actrow = i;
1014     }
1015     cursor.y -= top_baseline;
1016     cursor.x = top_x;
1017     x += top_x;
1018
1019     int swh;
1020     int sw = swh = SingleWidth(pain, par,cursor.pos);
1021     if (par->GetChar(cursor.pos)!=LyXParagraph::META_INSET)
1022         swh /= 2;
1023     int checkpos = rows[actrow + 1].pos;
1024     if ((actrow+2) < (int)rows.size())
1025         --checkpos;
1026     while ((cursor.pos < checkpos) && ((cursor.x + swh) < x)) {
1027         cursor.x += sw;
1028         ++cursor.pos;
1029         sw = swh = SingleWidth(pain, par,cursor.pos);
1030         if (par->GetChar(cursor.pos)!=LyXParagraph::META_INSET)
1031             swh /= 2;
1032     }
1033 }
1034
1035
1036 void InsetText::resetPos(Painter & pain) const
1037 {
1038     if (!rows.size())
1039         return;
1040
1041     int old_pos = cursor.pos;
1042
1043     cursor.y = top_baseline;
1044     actrow = 0;
1045     for(unsigned int i = 0; (i < (rows.size()-1)) && (rows[i].pos <= cursor.pos);
1046         ++i) {
1047         cursor.y = rows[i].baseline;
1048         actrow = i;
1049     }
1050     cursor.y -= top_baseline;
1051     setPos(pain, 0, cursor.y);
1052     cursor.x = top_x;
1053     while(cursor.pos < old_pos) {
1054         cursor.x += SingleWidth(pain, par,cursor.pos);
1055         ++cursor.pos;
1056     }
1057 }
1058
1059
1060 UpdatableInset::RESULT
1061 InsetText::moveRight(BufferView * bv, bool activate_inset)
1062 {
1063     if (cursor.pos >= par->Last())
1064         return FINISHED;
1065     if (activate_inset && checkAndActivateInset(bv)) {
1066         return DISPATCHED;
1067     }
1068     ++cursor.pos;
1069     resetPos(bv->painter());
1070     real_current_font = current_font = GetFont(par, cursor.pos);
1071     return DISPATCHED_NOUPDATE;
1072 }
1073
1074
1075 UpdatableInset::RESULT
1076 InsetText::moveLeft(BufferView * bv, bool activate_inset)
1077 {
1078     if (cursor.pos <= 0)
1079         return FINISHED;
1080     --cursor.pos;
1081     resetPos(bv->painter());
1082     if (activate_inset)
1083         if (checkAndActivateInset(bv, -1, -1))
1084             return DISPATCHED;
1085     return DISPATCHED_NOUPDATE;
1086 }
1087
1088
1089 UpdatableInset::RESULT
1090 InsetText::moveUp(BufferView * bv)
1091 {
1092     if (!actrow)
1093         return FINISHED;
1094     cursor.y = rows[actrow - 1].baseline - top_baseline;
1095     if (cursor.x_fix < 0)
1096         cursor.x_fix = cursor.x;
1097     setPos(bv->painter(), cursor.x_fix-top_x+drawTextXOffset, cursor.y);
1098     return DISPATCHED_NOUPDATE;
1099 }
1100
1101
1102 UpdatableInset::RESULT
1103 InsetText::moveDown(BufferView * bv)
1104 {
1105     if (actrow >= int(rows.size() - 2))
1106         return FINISHED;
1107     cursor.y = rows[actrow + 1].baseline - top_baseline;
1108     if (cursor.x_fix < 0)
1109         cursor.x_fix = cursor.x;
1110     setPos(bv->painter(), cursor.x_fix-top_x+drawTextXOffset, cursor.y);
1111     return DISPATCHED_NOUPDATE;
1112 }
1113
1114
1115 bool InsetText::Delete()
1116 {
1117     if ((par->GetChar(cursor.pos)==LyXParagraph::META_INSET) &&
1118         !par->GetInset(cursor.pos)->Deletable()) {
1119         return false;
1120     }
1121     par->Erase(cursor.pos);
1122     return true;
1123 }
1124
1125
1126 bool InsetText::InsertInset(BufferView * bv, Inset * inset)
1127 {
1128     bv->text->SetUndo(Undo::INSERT, 
1129               bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
1130               bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
1131     if (inset->Editable() == Inset::IS_EDITABLE) {
1132         UpdatableInset *i = (UpdatableInset *)inset;
1133         i->setOwner((UpdatableInset *)this);
1134     }
1135     par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1136     par->InsertInset(cursor.pos, inset);
1137     if (hasSelection()) {
1138         selection_start = selection_end = cursor.pos;
1139     } else {
1140         selection_start = selection_end = cursor.pos;
1141     }
1142     UpdateLocal(bv, true);
1143     static_cast<UpdatableInset*>(inset)->Edit(bv, 0, 0, 0);
1144     return true;
1145 }
1146
1147
1148 UpdatableInset * InsetText::GetLockingInset()
1149 {
1150     return the_locking_inset ? the_locking_inset->GetLockingInset() : this;
1151 }
1152
1153
1154 void InsetText::SetFont(BufferView * bv, LyXFont const & font, bool toggleall)
1155 {
1156     // if there is no selection just set the current_font
1157     if (!hasSelection()) {
1158         // Determine basis font
1159         LyXFont layoutfont;
1160         if (cursor.pos < BeginningOfMainBody(par))
1161             layoutfont = GetFont(par, -2);
1162         else
1163             layoutfont = GetFont(par, -1);
1164         
1165         // Update current font
1166         real_current_font.update(font, bv->buffer()->params.language_info,
1167                                  toggleall);
1168         
1169         // Reduce to implicit settings
1170         current_font = real_current_font;
1171         current_font.reduce(layoutfont);
1172         // And resolve it completely
1173         real_current_font.realize(layoutfont);
1174         return;
1175     }
1176     
1177     int s_start, s_end;
1178     if (selection_start > selection_end) {
1179         s_start = selection_end;
1180         s_end = selection_start;
1181     } else {
1182         s_start = selection_start;
1183         s_end = selection_end;
1184     }
1185     LyXFont newfont;
1186     while(s_start < s_end) {
1187         newfont = GetFont(par,s_start);
1188         newfont.update(font, bv->buffer()->params.language_info, toggleall);
1189         SetCharFont(s_start, newfont);
1190         ++s_start;
1191     }
1192     UpdateLocal(bv, true);
1193 }
1194
1195
1196 void InsetText::SetCharFont(int pos, LyXFont const & f)
1197 {
1198     /* let the insets convert their font */
1199         LyXFont font(f);
1200         
1201     if (par->GetChar(pos) == LyXParagraph::META_INSET) {
1202         if (par->GetInset(pos))
1203             font = par->GetInset(pos)->ConvertFont(font);
1204     }
1205     LyXLayout const & layout =
1206             textclasslist.Style(buffer->params.textclass,par->GetLayout());
1207
1208     // Get concrete layout font to reduce against
1209     LyXFont layoutfont;
1210
1211     if (pos < BeginningOfMainBody(par))
1212         layoutfont = layout.labelfont;
1213     else
1214         layoutfont = layout.font;
1215
1216
1217     layoutfont.realize((textclasslist.TextClass(buffer->params.textclass).
1218                        defaultfont()));
1219
1220     // Now, reduce font against full layout font
1221     font.reduce(layoutfont);
1222
1223     par->SetFont(pos, font);
1224 }
1225
1226
1227 void InsetText::computeTextRows(Painter & pain, float x) const
1228 {
1229     int p,
1230         nwp = 0,
1231         asc = 0,
1232         desc = 0,
1233         oasc = 0,
1234         odesc = 0,
1235         owidth = 0,
1236         wordAscent,
1237         wordDescent;
1238     row_struct row;
1239
1240     if (rows.size())
1241             rows.clear();
1242     int width = wordAscent = wordDescent = 0;
1243     insetWidth = maxAscent = maxDescent = 0;
1244     row.asc      = 0;
1245     row.desc     = 0;
1246     row.pos      = 0;
1247     row.baseline = 0;
1248     rows.push_back(row);
1249     if (!autoBreakRows) {
1250         for(p = 0; p < par->Last(); ++p) {
1251             insetWidth += SingleWidth(pain, par, p);
1252             SingleHeight(pain, par, p, asc, desc);
1253             maxAscent = max(maxAscent, asc);
1254             maxDescent = max(maxDescent, desc);
1255         }
1256         rows[0].asc = maxAscent;
1257         rows[0].desc = maxDescent;
1258         // alocate a dummy row for the endpos
1259         row.pos = par->Last();
1260         rows.push_back(row);
1261         return;
1262     }
1263
1264     bool is_first_word_in_row = true;
1265     int cw, lastWordWidth = 0;
1266     int maxWidth = getMaxTextWidth(pain, this, x);
1267
1268     for(p = 0; p < par->Last(); ++p) {
1269         cw = SingleWidth(pain, par, p);
1270         width += cw;
1271         lastWordWidth += cw;
1272         SingleHeight(pain, par, p, asc, desc);
1273         wordAscent = max(wordAscent, asc);
1274         wordDescent = max(wordDescent, desc);
1275         if (par->IsNewline(p)) {
1276             if (!is_first_word_in_row && (width >= maxWidth)) {
1277                 // we have to split also the row above
1278                 rows.back().asc = oasc;
1279                 rows.back().desc = odesc;
1280                 row.pos = nwp;
1281                 rows.push_back(row);
1282                 oasc = wordAscent;
1283                 odesc = wordDescent;
1284                 insetWidth = max(insetWidth, owidth);
1285                 width = lastWordWidth;
1286                 lastWordWidth = 0;
1287             }
1288             rows.back().asc = wordAscent;
1289             rows.back().desc = wordDescent;
1290             row.pos = ++p; // +1;
1291             rows.push_back(row);
1292             SingleHeight(pain, par, p, oasc, odesc);
1293             insetWidth = max(insetWidth, owidth);
1294             width = 0;
1295             is_first_word_in_row = true;
1296             wordAscent = wordDescent = lastWordWidth = 0;
1297             nwp = p;
1298             continue;
1299         }
1300         Inset const * inset = 0;
1301         if (((p + 1) < par->Last()) &&
1302             (par->GetChar(p + 1)==LyXParagraph::META_INSET))
1303             inset = par->GetInset(p + 1);
1304         if (inset && inset->display()) {
1305             if (!is_first_word_in_row && (width >= maxWidth)) {
1306                 // we have to split also the row above
1307                 rows.back().asc = oasc;
1308                 rows.back().desc = odesc;
1309                 row.pos = nwp;
1310                 rows.push_back(row);
1311                 oasc = wordAscent;
1312                 odesc = wordDescent;
1313                 insetWidth = max(insetWidth, owidth);
1314                 width = lastWordWidth;
1315                 lastWordWidth = 0;
1316             } else {
1317                     oasc = max(oasc, wordAscent);
1318                     odesc = max(odesc, wordDescent);
1319             }
1320             rows.back().asc = oasc;
1321             rows.back().desc = odesc;
1322             row.pos = ++p;
1323             rows.push_back(row);
1324             SingleHeight(pain, par, p, asc, desc);
1325             rows.back().asc = asc;
1326             rows.back().desc = desc;
1327             row.pos = nwp = p + 1;
1328             rows.push_back(row);
1329             oasc = odesc = width = lastWordWidth = 0;
1330             is_first_word_in_row = true;
1331             wordAscent = wordDescent = 0;
1332             continue;
1333         } else if (par->IsSeparator(p)) {
1334             if (width >= maxWidth) {
1335                 if (is_first_word_in_row) {
1336                     rows.back().asc = wordAscent;
1337                     rows.back().desc = wordDescent;
1338                     row.pos = p + 1;
1339                     rows.push_back(row);
1340                     oasc = odesc = width = 0;
1341                 } else {
1342                     rows.back().asc = oasc;
1343                     rows.back().desc = odesc;
1344                     row.pos = nwp;
1345                     rows.push_back(row);
1346                     oasc = wordAscent;
1347                     odesc = wordDescent;
1348                     insetWidth = max(insetWidth, owidth);
1349                     width = lastWordWidth;
1350                 }
1351                 wordAscent = wordDescent = lastWordWidth = 0;
1352                 nwp = p + 1;
1353                 continue;
1354             }
1355             owidth = width;
1356             oasc = max(oasc, wordAscent);
1357             odesc = max(odesc, wordDescent);
1358             wordAscent = wordDescent = lastWordWidth = 0;
1359             nwp = p + 1;
1360             is_first_word_in_row = false;
1361         }
1362     }
1363     // if we have some data in the paragraph we have ascent/descent
1364     if (p) {
1365         if (width >= maxWidth) {
1366             // assign upper row
1367             rows.back().asc = oasc;
1368             rows.back().desc = odesc;
1369             // assign and allocate lower row
1370             row.pos = nwp;
1371             rows.push_back(row);
1372             rows.back().asc = wordAscent;
1373             rows.back().desc = wordDescent;
1374             width -= lastWordWidth;
1375         } else {
1376             // assign last row data
1377             rows.back().asc = max(oasc, wordAscent);
1378             rows.back().desc = max(odesc, wordDescent);
1379         }
1380     }
1381     insetWidth = max(insetWidth, width);
1382     // alocate a dummy row for the endpos
1383     row.pos = par->Last();
1384     rows.push_back(row);
1385     // calculate maxAscent/Descent
1386     maxAscent = rows[0].asc;
1387     maxDescent = rows[0].desc;
1388     for (RowList::size_type i = 1; i < rows.size() - 1; ++i) {
1389         maxDescent += rows[i].asc + rows[i].desc + interline_space;
1390     }
1391 }
1392
1393
1394 void InsetText::computeBaselines(int baseline) const
1395 {
1396     rows[0].baseline = baseline;
1397     for (unsigned int i = 1; i < rows.size() - 1; i++) {
1398         rows[i].baseline = rows[i - 1].baseline + rows[i - 1].desc + 
1399             rows[i].asc + interline_space;
1400     }
1401 }
1402
1403 void InsetText::UpdateLocal(BufferView *bv, bool flag)
1404 {
1405 #if 1
1406     if (flag) {
1407         computeTextRows(bv->painter(), xpos);
1408         computeBaselines(top_baseline);
1409     }
1410     bv->updateInset(this, flag);
1411     if (flag)
1412         resetPos(bv->painter());
1413 #else
1414     init_inset = flag;
1415     bv->updateInset(this, flag);
1416 #endif
1417 }
1418
1419 bool InsetText::cutSelection()
1420 {
1421     if (!hasSelection())
1422         return false;
1423
1424     CutAndPaste cap;
1425
1426     LyXParagraph *endpar = par;
1427
1428     return cap.cutSelection(par, &endpar, selection_start, selection_end,
1429                             buffer->params.textclass);
1430 }
1431
1432 bool InsetText::copySelection()
1433 {
1434     if (!hasSelection())
1435         return false;
1436
1437     CutAndPaste cap;
1438
1439     return cap.copySelection(par, par, selection_start, selection_end,
1440                              buffer->params.textclass);
1441 }
1442
1443 bool InsetText::pasteSelection()
1444 {
1445     CutAndPaste cap;
1446
1447     if (cap.nrOfParagraphs() > 1) {
1448         WriteAlert(_("Impossible operation"),
1449                    _("Cannot include more than one paragraph!"),
1450                    _("Sorry."));
1451         return false;
1452     }
1453     LyXParagraph *endpar;
1454     LyXParagraph *actpar = par;
1455
1456     return cap.pasteSelection(&actpar, &endpar, cursor.pos,
1457                               buffer->params.textclass);
1458 }
1459
1460 bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y,
1461                                       int button)
1462 {
1463     if (par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
1464         UpdatableInset * inset =
1465             static_cast<UpdatableInset*>(par->GetInset(cursor.pos));
1466         LyXFont font = GetFont(par, cursor.pos);
1467         if (x < 0)
1468             x = inset->width(bv->painter(), font);
1469         if (y < 0)
1470             y = inset->descent(bv->painter(), font);
1471         inset_x = cursor.x - top_x + drawTextXOffset;
1472         inset_y = cursor.y + drawTextYOffset;
1473         inset->Edit(bv, x-inset_x, y-inset_y, button);
1474         if (!the_locking_inset)
1475             return false;
1476         UpdateLocal(bv, true);
1477         return true;
1478     }
1479     return false;
1480 }
1481
1482 int InsetText::getMaxTextWidth(Painter & pain, UpdatableInset const * inset,
1483                                int x) const
1484 {
1485     return getMaxWidth(pain, inset) - x;
1486 }