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