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