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