X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2Finsettext.C;h=e0b8f1f5b35ef77a7f2bdc85ec5bb3384fbc66f5;hb=3c8aba3b556871fb1100a2f98cd93d5d4e3f70c9;hp=54083dbacb29ec29708cc5f04d8be9aa4be7cbaa;hpb=e693ad9a4aa0dadeeb505ab0ab44b47fe953f283;p=lyx.git diff --git a/src/insets/insettext.C b/src/insets/insettext.C index 54083dbacb..e0b8f1f5b3 100644 --- a/src/insets/insettext.C +++ b/src/insets/insettext.C @@ -4,7 +4,7 @@ * * LyX, The Document Processor * - * Copyright 1998 The LyX Team. + * Copyright 1998-2000 The LyX Team. * * ====================================================== */ @@ -13,9 +13,6 @@ #include #include -using std::ifstream; -using std::min; -using std::max; #include @@ -54,8 +51,20 @@ using std::max; #include "support/LAssert.h" #include "lyxtext.h" #include "lyxcursor.h" +#include "CutAndPaste.h" +#include "font.h" +#include "minibuffer.h" +#include "toolbar.h" + +using std::ostream; +using std::ifstream; +using std::endl; +using std::min; +using std::max; extern unsigned char getCurrentTextClass(Buffer *); +extern LyXTextClass::size_type current_layout; + InsetText::InsetText(Buffer * buf) { @@ -67,35 +76,32 @@ InsetText::InsetText(Buffer * buf) InsetText::InsetText(InsetText const & ins, Buffer * buf) { par = 0; - init(buf, ins.par); + init(buf, &ins); + autoBreakRows = ins.autoBreakRows; } -void InsetText::init(Buffer * buf, LyXParagraph *p) + +void InsetText::init(Buffer * buf, InsetText const * ins) { - if (p) { - if (par) - delete par; - par = new LyXParagraph(p); - for(int pos = 0; pos < p->Last(); ++pos) { - par->InsertChar(pos, p->GetChar(pos)); - par->SetFont(pos, p->GetFontSettings(pos)); - if ((p->GetChar(pos) == LyXParagraph::META_INSET) && - p->GetInset(pos)) { - par->InsertInset(pos, p->GetInset(pos)->Clone()); - } - } - } the_locking_inset = 0; buffer = buf; cursor_visible = false; - maxWidth = old_x = -1; - actpos = selection_start = selection_end = 0; + cursor.x_fix = -1; interline_space = 1; no_selection = false; init_inset = true; - maxAscent = maxDescent = insetWidth = widthOffset = 0; + maxAscent = maxDescent = insetWidth = 0; + drawTextXOffset = drawTextYOffset = 0; autoBreakRows = false; xpos = 0.0; + if (ins) { + SetParagraphData(ins->par); + autoBreakRows = ins->autoBreakRows; + } + par->SetInsetOwner(this); + cursor.par = par; + cursor.pos = 0; + selection_start_cursor = selection_end_cursor = cursor; } @@ -137,6 +143,7 @@ void InsetText::Read(LyXLex & lex) delete par; par = new LyXParagraph; + par->SetInsetOwner(this); while (lex.IsOK()) { lex.nextToken(); @@ -166,11 +173,12 @@ int InsetText::ascent(Painter & pain, LyXFont const & font) const { if (init_inset) { computeTextRows(pain, xpos); + resetPos(pain); init_inset = false; } if (maxAscent) return maxAscent; - return font.maxAscent(); + return lyxfont::maxAscent(font); } @@ -178,11 +186,12 @@ int InsetText::descent(Painter & pain, LyXFont const & font) const { if (init_inset) { computeTextRows(pain, xpos); + resetPos(pain); init_inset = false; } if (maxDescent) return maxDescent; - return font.maxDescent(); + return lyxfont::maxDescent(font); } @@ -190,6 +199,7 @@ int InsetText::width(Painter & pain, LyXFont const &) const { if (init_inset) { computeTextRows(pain, xpos); + resetPos(pain); init_inset = false; } return insetWidth; @@ -200,12 +210,22 @@ void InsetText::draw(Painter & pain, LyXFont const & f, int baseline, float & x) const { xpos = x; - computeTextRows(pain, x); UpdatableInset::draw(pain, f, baseline, x); - top_x = int(x); - top_baseline = baseline; - computeBaselines(baseline); + if (init_inset || (baseline != top_baseline) || (top_x != int(x))) { + top_baseline = baseline; + if (init_inset || (top_x != int(x))) { + top_x = int(x); + computeTextRows(pain, x); + init_inset = false; + } + computeBaselines(baseline); + } + if (the_locking_inset && (cursor.pos == inset_pos)) { + resetPos(pain); + inset_x = cursor.x - top_x + drawTextXOffset; + inset_y = cursor.y + drawTextYOffset; + } for(RowList::size_type r = 0; r < rows.size() - 1; ++r) { drawRowSelection(pain, rows[r].pos, rows[r + 1].pos, r, rows[r].baseline, x); @@ -222,12 +242,12 @@ void InsetText::drawRowSelection(Painter & pain, int startpos, int endpos, return; int s_start, s_end; - if (selection_start > selection_end) { - s_start = selection_end; - s_end = selection_start; + if (selection_start_cursor.pos > selection_end_cursor.pos) { + s_start = selection_end_cursor.pos; + s_end = selection_start_cursor.pos; } else { - s_start = selection_start; - s_end = selection_end; + s_start = selection_start_cursor.pos; + s_end = selection_end_cursor.pos; } if ((s_start > endpos) || (s_end < startpos)) return; @@ -242,14 +262,14 @@ void InsetText::drawRowSelection(Painter & pain, int startpos, int endpos, if ((p >= s_start) && (p <= s_end)) esel_x = int(x); char ch = par->GetChar(p); - font = GetFont(par,p); + font = GetDrawFont(par,p); if (IsFloatChar(ch)) { // skip for now } else if (ch == LyXParagraph::META_INSET) { Inset const * tmpinset = par->GetInset(p); x += tmpinset->width(pain, font); } else { - x += pain.width(ch,font); + x += lyxfont::width(ch, font); } } if (p == s_start) @@ -272,13 +292,13 @@ void InsetText::drawRowText(Painter & pain, int startpos, int endpos, for(int p = startpos; p < endpos; ++p) { char ch = par->GetChar(p); - LyXFont font = GetFont(par,p); + LyXFont font = GetDrawFont(par,p); if (IsFloatChar(ch)) { // skip for now } else if (par->IsNewline(p)) { // Draw end-of-line marker - int wid = font.width('n'); - int asc = font.maxAscent(); + int wid = lyxfont::width('n', font); + int asc = lyxfont::maxAscent(font); int y = baseline; int xp[3], yp[3]; @@ -310,7 +330,7 @@ void InsetText::drawRowText(Painter & pain, int startpos, int endpos, tmpinset->draw(pain, font, baseline, x); } else { pain.text(int(x), baseline, ch, font); - x += pain.width(ch,font); + x += lyxfont::width(ch, font); } } } @@ -324,34 +344,74 @@ char const * InsetText::EditMessage() const void InsetText::Edit(BufferView * bv, int x, int y, unsigned int button) { + par->SetInsetOwner(this); UpdatableInset::Edit(bv, x, y, button); - bv->lockInset(this); + if (!bv->lockInset(this)) { + lyxerr[Debug::INSETS] << "Cannot lock inset" << endl; + return; + } the_locking_inset = 0; inset_pos = inset_x = inset_y = 0; - no_selection = true; - setPos(bv, x,y); - selection_start = selection_end = actpos; - current_font = real_current_font = GetFont(par, actpos); + setPos(bv->painter(), x, y); + checkAndActivateInset(bv, x, y, button); + selection_start_cursor = selection_end_cursor = cursor; + current_font = real_current_font = GetFont(par, cursor.pos); bv->text->FinishUndo(); + UpdateLocal(bv, true); } void InsetText::InsetUnlock(BufferView * bv) { - if (the_locking_inset) + if (the_locking_inset) { the_locking_inset->InsetUnlock(bv); + the_locking_inset = 0; + } HideInsetCursor(bv); + lyxerr[Debug::INSETS] << "InsetText::InsetUnlock(" << this << + ")" << endl; if (hasSelection()) { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; UpdateLocal(bv, false); } - the_locking_inset = 0; no_selection = false; } -bool InsetText::UnlockInsetInInset(BufferView * bv, Inset * inset, bool lr) +bool InsetText::LockInsetInInset(BufferView * bv, UpdatableInset * inset) +{ + lyxerr[Debug::INSETS] << "InsetText::LockInsetInInset(" << inset << "): "; + if (!inset) + return false; + if (inset == par->GetInset(cursor.pos)) { + lyxerr[Debug::INSETS] << "OK" << endl; + the_locking_inset = inset; + resetPos(bv->painter()); + inset_x = cursor.x - top_x + drawTextXOffset; + inset_y = cursor.y + drawTextYOffset; + inset_pos = cursor.pos; + return true; + } else if (the_locking_inset && (the_locking_inset == inset)) { + if (cursor.pos == inset_pos) { + lyxerr[Debug::INSETS] << "OK" << endl; + resetPos(bv->painter()); + inset_x = cursor.x - top_x + drawTextXOffset; + inset_y = cursor.y + drawTextYOffset; + } else { + lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl; + } + } else if (the_locking_inset) { + lyxerr[Debug::INSETS] << "MAYBE" << endl; + return the_locking_inset->LockInsetInInset(bv, inset); + } + lyxerr[Debug::INSETS] << "NOT OK" << endl; + return false; +} + + +bool InsetText::UnlockInsetInInset(BufferView * bv, UpdatableInset * inset, + bool lr) { if (!the_locking_inset) return false; @@ -362,7 +422,7 @@ bool InsetText::UnlockInsetInInset(BufferView * bv, Inset * inset, bool lr) moveRight(bv, false); return true; } - return the_locking_inset->UnlockInsetInInset(bv, inset,lr); + return the_locking_inset->UnlockInsetInInset(bv, inset, lr); } @@ -372,74 +432,103 @@ bool InsetText::UpdateInsetInInset(BufferView * bv, Inset * inset) return false; if (the_locking_inset != inset) return the_locking_inset->UpdateInsetInInset(bv, inset); - float x = inset_x; - inset->draw(bv->getPainter(), real_current_font, inset_y, x); + lyxerr[Debug::INSETS] << "InsetText::UpdateInsetInInset(" << inset << + ")" << endl; UpdateLocal(bv, true); - return true; -} - - -void InsetText::InsetButtonRelease(BufferView * bv, int x, int y, int button) -{ - if (the_locking_inset) { - the_locking_inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button); - return; + if (cursor.pos == inset_pos) { + inset_x = cursor.x - top_x + drawTextXOffset; + inset_y = cursor.y + drawTextYOffset; } - no_selection = false; + return true; } void InsetText::InsetButtonPress(BufferView * bv, int x, int y, int button) { if (hasSelection()) { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; UpdateLocal(bv, false); } no_selection = false; + setPos(bv->painter(), x, y); + cursor.x_fix = -1; if (the_locking_inset) { - setPos(bv, x, y, false); UpdatableInset *inset = 0; - if (par->GetChar(actpos) == LyXParagraph::META_INSET) - inset = static_cast(par->GetInset(actpos)); + if (par->GetChar(cursor.pos) == LyXParagraph::META_INSET) + inset = static_cast(par->GetInset(cursor.pos)); if (the_locking_inset == inset) { the_locking_inset->InsetButtonPress(bv,x-inset_x,y-inset_y,button); return; } else if (inset) { // otherwise unlock the_locking_inset and lock the new inset - inset_x = cx-top_x; - inset_y = cy; - inset_pos = actpos; the_locking_inset->InsetUnlock(bv); - the_locking_inset = inset; - the_locking_inset->Edit(bv, x - inset_x, y - inset_y, button); + inset_x = cursor.x - top_x + drawTextXOffset; + inset_y = cursor.y + drawTextYOffset; + inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button); + inset->Edit(bv, x - inset_x, y - inset_y, button); + UpdateLocal(bv, true); return; } // otherwise only unlock the_locking_inset the_locking_inset->InsetUnlock(bv); + the_locking_inset = 0; } - HideInsetCursor(bv); - the_locking_inset = 0; - setPos(bv, x, y); - selection_start = selection_end = actpos; - if (!the_locking_inset) - ShowInsetCursor(bv); + if (bv->the_locking_inset) { + if ((par->GetChar(cursor.pos) == LyXParagraph::META_INSET) && + par->GetInset(cursor.pos) && + (par->GetInset(cursor.pos)->Editable() == Inset::HIGHLY_EDITABLE)) { + UpdatableInset *inset = + static_cast(par->GetInset(cursor.pos)); + inset_x = cursor.x - top_x + drawTextXOffset; + inset_y = cursor.y + drawTextYOffset; + inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button); + inset->Edit(bv, x-inset_x, y-inset_y, 0); + UpdateLocal(bv, true); + } + } + selection_start_cursor = selection_end_cursor = cursor; } -void InsetText::InsetMotionNotify(BufferView * bv, int x, int y, int button) +void InsetText::InsetButtonRelease(BufferView * bv, int x, int y, int button) +{ + UpdatableInset * inset = 0; + + if (the_locking_inset) { + the_locking_inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button); + } else { + if (par->GetChar(cursor.pos) == LyXParagraph::META_INSET) { + inset = static_cast(par->GetInset(cursor.pos)); + if (inset->Editable()==Inset::HIGHLY_EDITABLE) { + inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button); + } else { + inset_x = cursor.x - top_x + drawTextXOffset; + inset_y = cursor.y + drawTextYOffset; + inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button); + inset->Edit(bv, x-inset_x, y-inset_y, button); + } + } + } + no_selection = false; +} + + +void InsetText::InsetMotionNotify(BufferView * bv, int x, int y, int state) { if (the_locking_inset) { the_locking_inset->InsetMotionNotify(bv, x - inset_x, - y - inset_y,button); + y - inset_y,state); return; } if (!no_selection) { - int old = selection_end; - setPos(bv, x, y, false); - selection_end = actpos; - if (old != selection_end) + LyXCursor old = selection_end_cursor; + HideInsetCursor(bv); + setPos(bv->painter(), x, y); + selection_end_cursor = cursor; + if (old != selection_end_cursor) UpdateLocal(bv, false); + ShowInsetCursor(bv); } no_selection = false; } @@ -459,31 +548,39 @@ InsetText::LocalDispatch(BufferView * bv, int action, string const & arg) { no_selection = false; - if (UpdatableInset::LocalDispatch(bv, action, arg)) { - resetPos(bv); + UpdatableInset::RESULT + result= UpdatableInset::LocalDispatch(bv, action, arg); + if (result != UNDISPATCHED) { + resetPos(bv->painter()); return DISPATCHED; } - UpdatableInset::RESULT - result=DISPATCHED; - + result=DISPATCHED; if ((action < 0) && arg.empty()) return FINISHED; if ((action != LFUN_DOWN) && (action != LFUN_UP) && (action != LFUN_DOWNSEL) && (action != LFUN_UPSEL)) - old_x = -1; + cursor.x_fix = -1; if (the_locking_inset) { result = the_locking_inset->LocalDispatch(bv, action, arg); - if (result == DISPATCHED) { + if (result == DISPATCHED_NOUPDATE) + return result; + else if (result == DISPATCHED) { the_locking_inset->ToggleInsetCursor(bv); UpdateLocal(bv, false); the_locking_inset->ToggleInsetCursor(bv); return result; } else if (result == FINISHED) { - if ((action == LFUN_RIGHT) || (action == -1)) { - actpos = inset_pos + 1; - resetPos(bv); + switch(action) { + case -1: + case LFUN_RIGHT: + cursor.pos = inset_pos + 1; + resetPos(bv->painter()); + break; + case LFUN_DOWN: + moveDown(bv); + break; } the_locking_inset = 0; return DISPATCHED; @@ -497,146 +594,160 @@ InsetText::LocalDispatch(BufferView * bv, bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous, bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next); cutSelection(); - actpos = selection_start; - par->InsertChar(actpos,arg[0]); - par->SetFont(actpos,real_current_font); - ++actpos; - selection_start = selection_end = actpos; + cursor = selection_start_cursor; + par->InsertChar(cursor.pos,arg[0]); + SetCharFont(cursor.pos,current_font); + ++cursor.pos; + selection_start_cursor = selection_end_cursor = cursor; UpdateLocal(bv, true); break; // --- Cursor Movements --------------------------------------------- case LFUN_RIGHTSEL: bv->text->FinishUndo(); moveRight(bv, false); - selection_end = actpos; + selection_end_cursor = cursor; UpdateLocal(bv, false); break; case LFUN_RIGHT: bv->text->FinishUndo(); - result= DISPATCH_RESULT(moveRight(bv)); + result = moveRight(bv); if (hasSelection()) { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; UpdateLocal(bv, false); } else { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; } break; case LFUN_LEFTSEL: bv->text->FinishUndo(); moveLeft(bv, false); - selection_end = actpos; + selection_end_cursor = cursor; UpdateLocal(bv, false); break; case LFUN_LEFT: bv->text->FinishUndo(); - result= DISPATCH_RESULT(moveLeft(bv)); + result= moveLeft(bv); if (hasSelection()) { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; UpdateLocal(bv, false); } else { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; } break; case LFUN_DOWNSEL: bv->text->FinishUndo(); - moveDown(bv, false); - selection_end = actpos; + moveDown(bv); + selection_end_cursor = cursor; UpdateLocal(bv, false); break; case LFUN_DOWN: bv->text->FinishUndo(); - result= DISPATCH_RESULT(moveDown(bv)); + result = moveDown(bv); if (hasSelection()) { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; UpdateLocal(bv, false); } else { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; } break; case LFUN_UPSEL: bv->text->FinishUndo(); - moveUp(bv, false); - selection_end = actpos; + moveUp(bv); + selection_end_cursor = cursor; UpdateLocal(bv, false); break; case LFUN_UP: bv->text->FinishUndo(); - result= DISPATCH_RESULT(moveUp(bv)); + result = moveUp(bv); if (hasSelection()) { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; UpdateLocal(bv, false); } else { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; } break; case LFUN_BACKSPACE: - if (!actpos) { // || par->IsNewline(actpos-1)) { + if (!cursor.pos) { if (hasSelection()) { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; UpdateLocal(bv, false); } break; } moveLeft(bv); case LFUN_DELETE: - bool ret; + { bv->text->SetUndo(Undo::DELETE, bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous, bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next); - if (hasSelection()) - ret = cutSelection(); - else + bool ret = true; + if (hasSelection()) { + LyXParagraph::size_type i = selection_start_cursor.pos; + for (; i < selection_end_cursor.pos; ++i) { + par->Erase(selection_start_cursor.pos); + } + } else ret = Delete(); if (ret) { // we need update - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; UpdateLocal(bv, true); } else if (hasSelection()) { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; UpdateLocal(bv, false); } - break; + } + resetPos(bv->painter()); + break; case LFUN_CUT: - bv->text->SetUndo(Undo::DELETE, - bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous, - bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next); - if (cutSelection()) { // we need update - actpos = selection_end = selection_start; + bv->text->SetUndo(Undo::DELETE, + bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous, + bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next); + + if (cutSelection()) { + // we need update + cursor = selection_end_cursor = selection_start_cursor; UpdateLocal(bv, true); } else if (hasSelection()) { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; UpdateLocal(bv, false); } + resetPos(bv->painter()); break; case LFUN_COPY: bv->text->FinishUndo(); - if (copySelection()) { // we need update - selection_start = selection_end = actpos; + if (copySelection()) { + // we need update + selection_start_cursor = selection_end_cursor = cursor; UpdateLocal(bv, true); } else if (hasSelection()) { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; UpdateLocal(bv, false); } break; case LFUN_PASTE: + { bv->text->SetUndo(Undo::INSERT, - bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous, - bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next); + bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous, + bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next); if (pasteSelection()) { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; UpdateLocal(bv, true); } - break; + } + resetPos(bv->painter()); + break; case LFUN_HOME: bv->text->FinishUndo(); - for(; actpos > rows[actrow].pos; --actpos) - cx -= SingleWidth(bv->getPainter(), par, actpos); - cx -= SingleWidth(bv->getPainter(), par, actpos); + for(; cursor.pos > rows[actrow].pos; --cursor.pos) + cursor.x -= SingleWidth(bv->painter(), par, cursor.pos); + cursor.x -= SingleWidth(bv->painter(), par, cursor.pos); if (hasSelection()) { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; UpdateLocal(bv, false); } else { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; } + resetPos(bv->painter()); break; case LFUN_END: { @@ -644,57 +755,87 @@ InsetText::LocalDispatch(BufferView * bv, int checkpos = (int)rows[actrow + 1].pos; if ((actrow + 2) < (int)rows.size()) --checkpos; - for(; actpos < checkpos; ++actpos) - cx += SingleWidth(bv->getPainter(), par, actpos); + for(; cursor.pos < checkpos; ++cursor.pos) + cursor.x += SingleWidth(bv->painter(), par, cursor.pos); if (hasSelection()) { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; UpdateLocal(bv, false); } else { - selection_start = selection_end = actpos; + selection_start_cursor = selection_end_cursor = cursor; } } + resetPos(bv->painter()); break; - case LFUN_MATH_MODE: // Open or create a math inset - bv->text->SetUndo(Undo::INSERT, - bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous, - bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next); + case LFUN_MATH_MODE: InsertInset(bv, new InsetFormula); - if (hasSelection()) { - selection_start = selection_end = actpos; - UpdateLocal(bv, false); - } else { - selection_start = selection_end = actpos; - } return DISPATCHED; + case LFUN_INSET_ERT: + InsertInset(bv, new InsetERT(buffer)); + return DISPATCHED; + case LFUN_BREAKPARAGRAPH: case LFUN_BREAKLINE: + if (!autoBreakRows) + return DISPATCHED; bv->text->SetUndo(Undo::INSERT, bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous, bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next); - par->InsertChar(actpos,LyXParagraph::META_NEWLINE); - par->SetFont(actpos,real_current_font); + par->InsertChar(cursor.pos,LyXParagraph::META_NEWLINE); + SetCharFont(cursor.pos,current_font); UpdateLocal(bv, true); - ++actpos; - selection_start = selection_end = actpos; - resetPos(bv); + ++cursor.pos; + selection_start_cursor = selection_end_cursor = cursor; + resetPos(bv->painter()); break; + case LFUN_LAYOUT: + { + // Derive layout number from given argument (string) + // and current buffer's textclass (number). */ + LyXTextClassList::ClassList::size_type tclass = + buffer->params.textclass; + std::pair layout = + textclasslist.NumberOfLayout(tclass, arg); + + // If the entry is obsolete, use the new one instead. + if (layout.first) { + string obs = textclasslist.Style(tclass,layout.second). + obsoleted_by(); + if (!obs.empty()) + layout = textclasslist.NumberOfLayout(tclass, obs); + } + + // see if we found the layout number: + if (!layout.first) { + string msg = string(N_("Layout ")) + arg + N_(" not known"); + + bv->owner()->getMiniBuffer()->Set(msg); + break; + } + + if (current_layout != layout.second) { + bv->text->SetLayout(cursor, selection_start_cursor, + selection_end_cursor, layout.second); + bv->owner()->getToolbar()->combox->select(cursor.par->GetLayout()+1); + UpdateLocal(bv, true); + } + } + break; default: result = UNDISPATCHED; break; } if (result != FINISHED) { - if (!the_locking_inset) - ShowInsetCursor(bv); + ShowInsetCursor(bv); } else bv->unlockInset(this); return result; } -int InsetText::Latex(ostream & os, signed char /*fragile*/, bool) const +int InsetText::Latex(ostream & os, bool /*fragile*/, bool /*fp*/) const { - TexRow texrow; - int ret = par->SimpleTeXOnePar(os, texrow); - return ret; + TexRow texrow; + buffer->latexParagraphs(os, par, 0, texrow); + return texrow.rows(); } @@ -707,11 +848,11 @@ void InsetText::Validate(LaTeXFeatures & features) const // Returns the width of a character at a certain spot int InsetText::SingleWidth(Painter & pain, LyXParagraph * par, int pos) const { - LyXFont font = GetFont(par, pos); + LyXFont font = GetDrawFont(par, pos); char c = par->GetChar(pos); if (IsPrintable(c)) { - return font.width(c); + return lyxfont::width(c, font); } else if (c == LyXParagraph::META_INSET) { Inset const * tmpinset = par->GetInset(pos); if (tmpinset) @@ -722,7 +863,7 @@ int InsetText::SingleWidth(Painter & pain, LyXParagraph * par, int pos) const c = ' '; else if (IsNewlineChar(c)) c = 'n'; - return font.width(c); + return lyxfont::width(c, font); } @@ -730,7 +871,7 @@ int InsetText::SingleWidth(Painter & pain, LyXParagraph * par, int pos) const void InsetText::SingleHeight(Painter & pain, LyXParagraph * par,int pos, int & asc, int & desc) const { - LyXFont font = GetFont(par, pos); + LyXFont font = GetDrawFont(par, pos); char c = par->GetChar(pos); asc = desc = 0; @@ -741,8 +882,8 @@ void InsetText::SingleHeight(Painter & pain, LyXParagraph * par,int pos, desc = tmpinset->descent(pain, font); } } else { - asc = font.maxAscent(); - desc = font.maxDescent(); + asc = lyxfont::maxAscent(font); + desc = lyxfont::maxDescent(font); } return; } @@ -821,6 +962,13 @@ LyXFont InsetText::GetFont(LyXParagraph * par, int pos) const } +// the font for drawing may be different from the real font +LyXFont InsetText::GetDrawFont(LyXParagraph * par, int pos) const +{ + return GetFont(par, pos); +} + + int InsetText::BeginningOfMainBody(LyXParagraph * par) const { if (textclasslist.Style(buffer->params.textclass, @@ -833,8 +981,8 @@ int InsetText::BeginningOfMainBody(LyXParagraph * par) const void InsetText::GetCursorPos(int & x, int & y) const { - x = cx; - y = cy; + x = cursor.x; + y = cursor.y; } @@ -843,8 +991,7 @@ int InsetText::InsetInInsetY() if (!the_locking_inset) return 0; - int y = inset_y; - return (y + the_locking_inset->InsetInInsetY()); + return (inset_y + the_locking_inset->InsetInInsetY()); } @@ -855,28 +1002,32 @@ void InsetText::ToggleInsetCursor(BufferView * bv) return; } - LyXFont font = GetFont(par, actpos); + LyXFont font = GetDrawFont(par, cursor.pos); - int asc = font.maxAscent(); - int desc = font.maxDescent(); + int asc = lyxfont::maxAscent(font); + int desc = lyxfont::maxDescent(font); if (cursor_visible) bv->hideLockedInsetCursor(); else - bv->showLockedInsetCursor(cx, cy, asc, desc); + bv->showLockedInsetCursor(cursor.x, cursor.y, asc, desc); cursor_visible = !cursor_visible; } void InsetText::ShowInsetCursor(BufferView * bv) { + if (the_locking_inset) { + the_locking_inset->ShowInsetCursor(bv); + return; + } if (!cursor_visible) { - LyXFont font = GetFont(par, actpos); + LyXFont font = GetDrawFont(par, cursor.pos); - int asc = font.maxAscent(); - int desc = font.maxDescent(); - bv->fitLockedInsetCursor(cx, cy, asc, desc); - bv->showLockedInsetCursor(cx, cy, asc, desc); + int asc = lyxfont::maxAscent(font); + int desc = lyxfont::maxDescent(font); + bv->fitLockedInsetCursor(cursor.x, cursor.y, asc, desc); + bv->showLockedInsetCursor(cursor.x, cursor.y, asc, desc); cursor_visible = true; } } @@ -884,175 +1035,162 @@ void InsetText::ShowInsetCursor(BufferView * bv) void InsetText::HideInsetCursor(BufferView * bv) { - if (cursor_visible) - ToggleInsetCursor(bv); + if (cursor_visible) { + bv->hideLockedInsetCursor(); + cursor_visible = false; + } + if (the_locking_inset) + the_locking_inset->HideInsetCursor(bv); } -void InsetText::setPos(BufferView * bv, int x, int y, bool activate_inset) +void InsetText::setPos(Painter & pain, int x, int y) const { - int ox = x; - int oy = y; - + x -= drawTextXOffset; + y -= drawTextYOffset; // search right X-pos x==0 -> top_x - actpos = actrow = 0; - cy = top_baseline; - y += cy; + cursor.pos = actrow = 0; + cursor.y = top_baseline; + y += cursor.y; for(unsigned int i = 1; - ((cy + rows[i - 1].desc) < y) && (i < rows.size() - 1); ++i) { - cy = rows[i].baseline; - actpos = rows[i].pos; + (long(cursor.y + rows[i - 1].desc) < y) + && (i < rows.size() - 1); ++i) { + cursor.y = rows[i].baseline; + cursor.pos = rows[i].pos; actrow = i; } - cy -= top_baseline; - cx = top_x; + cursor.y -= top_baseline; + cursor.x = top_x; x += top_x; int swh; - int sw; - int checkpos; - - sw = swh = SingleWidth(bv->getPainter(), par,actpos); - if (par->GetChar(actpos)!=LyXParagraph::META_INSET) + int sw = swh = SingleWidth(pain, par,cursor.pos); + if (par->GetChar(cursor.pos)!=LyXParagraph::META_INSET) swh /= 2; - checkpos = rows[actrow + 1].pos; + int checkpos = rows[actrow + 1].pos; if ((actrow+2) < (int)rows.size()) --checkpos; - while ((actpos < checkpos) && ((cx + swh) < x)) { - cx += sw; - ++actpos; - sw = swh = SingleWidth(bv->getPainter(), par,actpos); - if (par->GetChar(actpos)!=LyXParagraph::META_INSET) + while ((cursor.pos < checkpos) && ((cursor.x + swh) < x)) { + cursor.x += sw; + ++cursor.pos; + sw = swh = SingleWidth(pain, par,cursor.pos); + if (par->GetChar(cursor.pos)!=LyXParagraph::META_INSET) swh /= 2; } - if (activate_inset && par->GetChar(actpos)==LyXParagraph::META_INSET) { - the_locking_inset = - static_cast(par->GetInset(actpos)); - inset_x = cx - top_x; - inset_y = cy; - inset_pos = actpos; - the_locking_inset->Edit(bv, ox - inset_x, oy - inset_y, 0); - } } -bool InsetText::moveRight(BufferView * bv, bool activate_inset) +void InsetText::resetPos(Painter & pain) const { - if (actpos >= par->Last()) - return false; - if (activate_inset && par->GetChar(actpos)==LyXParagraph::META_INSET) { - the_locking_inset = - static_cast(par->GetInset(actpos)); - inset_x = cx - top_x; - inset_y = cy; - inset_pos = actpos; - the_locking_inset->Edit(bv, 0, 0, 0); - } else { - ++actpos; - resetPos(bv); + cursor.par = par; + + if (!rows.size()) + return; + + int old_pos = cursor.pos; + + cursor.y = top_baseline; + actrow = 0; + for(unsigned int i = 0; + (i < (rows.size()-1)) && (rows[i].pos <= cursor.pos); + ++i) { + cursor.y = rows[i].baseline; + actrow = i; + } + cursor.y -= top_baseline; + setPos(pain, 0, cursor.y); + cursor.x = top_x; + while(cursor.pos < old_pos) { + cursor.x += SingleWidth(pain, par,cursor.pos); + ++cursor.pos; } - return true; } -bool InsetText::moveLeft(BufferView * bv, bool activate_inset) +UpdatableInset::RESULT +InsetText::moveRight(BufferView * bv, bool activate_inset) { - if (actpos <= 0) - return false; - --actpos; - if (activate_inset && par->GetChar(actpos)==LyXParagraph::META_INSET) { - the_locking_inset = - static_cast(par->GetInset(actpos)); - resetPos(bv); - inset_x = cx - top_x; - inset_y = cy; - inset_pos = actpos; - the_locking_inset->Edit(bv, the_locking_inset-> - width(bv->getPainter(), GetFont(par,actpos)), - 0, 0); - } else { - resetPos(bv); + if (cursor.pos >= par->Last()) + return FINISHED; + if (activate_inset && checkAndActivateInset(bv)) { + return DISPATCHED; } - return true; + ++cursor.pos; + resetPos(bv->painter()); + real_current_font = current_font = GetFont(par, cursor.pos); + return DISPATCHED_NOUPDATE; } -bool InsetText::moveUp(BufferView * bv, bool activate_inset) +UpdatableInset::RESULT +InsetText::moveLeft(BufferView * bv, bool activate_inset) { - if (!actrow) - return false; - cy = rows[actrow - 1].baseline - top_baseline; - setPos(bv, cx - top_x, cy, activate_inset); - return true; + if (cursor.pos <= 0) + return FINISHED; + --cursor.pos; + resetPos(bv->painter()); + if (activate_inset) + if (checkAndActivateInset(bv, -1, -1)) + return DISPATCHED; + return DISPATCHED_NOUPDATE; } -bool InsetText::moveDown(BufferView * bv, bool activate_inset) +UpdatableInset::RESULT +InsetText::moveUp(BufferView * bv) { - if (actrow >= int(rows.size() - 2)) - return false; - cy = rows[actrow + 1].baseline - top_baseline; - setPos(bv, cx - top_x, cy, activate_inset); - return true; + if (!actrow) + return FINISHED; + cursor.y = rows[actrow - 1].baseline - top_baseline; + if (cursor.x_fix < 0) + cursor.x_fix = cursor.x; + setPos(bv->painter(), cursor.x_fix-top_x+drawTextXOffset, cursor.y); + return DISPATCHED_NOUPDATE; } -void InsetText::resetPos(BufferView * bv) +UpdatableInset::RESULT +InsetText::moveDown(BufferView * bv) { - if (!rows.size()) - return; - - int old_pos = actpos; - - cy = top_baseline; - actrow = 0; - for(unsigned int i = 0; (i < (rows.size()-1)) && (rows[i].pos <= actpos); - ++i) { - cy = rows[i].baseline; - actrow = i; - } - cy -= top_baseline; - setPos(bv, 0, cy, false); - cx = top_x; - while(actpos < old_pos) { - cx += SingleWidth(bv->getPainter(), par,actpos); - ++actpos; - } + if (actrow >= int(rows.size() - 2)) + return FINISHED; + cursor.y = rows[actrow + 1].baseline - top_baseline; + if (cursor.x_fix < 0) + cursor.x_fix = cursor.x; + setPos(bv->painter(), cursor.x_fix-top_x+drawTextXOffset, cursor.y); + return DISPATCHED_NOUPDATE; } bool InsetText::Delete() { - /* some insets are undeletable here */ - if (par->GetChar(actpos)==LyXParagraph::META_INSET) { - /* force complete redo when erasing display insets */ - /* this is a cruel method but save..... Matthias */ - if (par->GetInset(actpos)->Deletable() && - par->GetInset(actpos)->display()) { - par->Erase(actpos); - return true; - } - return false; + if ((par->GetChar(cursor.pos)==LyXParagraph::META_INSET) && + !par->GetInset(cursor.pos)->Deletable()) { + return false; } - par->Erase(actpos); + par->Erase(cursor.pos); return true; } bool InsetText::InsertInset(BufferView * bv, Inset * inset) { + bv->text->SetUndo(Undo::INSERT, + bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous, + bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next); if (inset->Editable() == Inset::IS_EDITABLE) { UpdatableInset *i = (UpdatableInset *)inset; i->setOwner((UpdatableInset *)this); } - par->InsertChar(actpos, LyXParagraph::META_INSET); - par->InsertInset(actpos, inset); + par->InsertChar(cursor.pos, LyXParagraph::META_INSET); + par->InsertInset(cursor.pos, inset); + if (hasSelection()) { + selection_start_cursor = selection_end_cursor = cursor; + } else { + selection_start_cursor = selection_end_cursor = cursor; + } UpdateLocal(bv, true); - the_locking_inset = static_cast(inset); - inset_x = cx - top_x; - inset_y = cy; - inset_pos = actpos; - inset->Edit(bv, 0, 0, 0); + static_cast(inset)->Edit(bv, 0, 0, 0); return true; } @@ -1069,7 +1207,7 @@ void InsetText::SetFont(BufferView * bv, LyXFont const & font, bool toggleall) if (!hasSelection()) { // Determine basis font LyXFont layoutfont; - if (actpos < BeginningOfMainBody(par)) + if (cursor.pos < BeginningOfMainBody(par)) layoutfont = GetFont(par, -2); else layoutfont = GetFont(par, -1); @@ -1087,12 +1225,12 @@ void InsetText::SetFont(BufferView * bv, LyXFont const & font, bool toggleall) } int s_start, s_end; - if (selection_start > selection_end) { - s_start = selection_end; - s_end = selection_start; + if (selection_start_cursor.pos > selection_end_cursor.pos) { + s_start = selection_end_cursor.pos; + s_end = selection_start_cursor.pos; } else { - s_start = selection_start; - s_end = selection_end; + s_start = selection_start_cursor.pos; + s_end = selection_end_cursor.pos; } LyXFont newfont; while(s_start < s_end) { @@ -1174,10 +1312,9 @@ void InsetText::computeTextRows(Painter & pain, float x) const } bool is_first_word_in_row = true; - int cw, lastWordWidth = 0; + int maxWidth = getMaxTextWidth(pain, this, x); - maxWidth = getMaxWidth(pain) - widthOffset; for(p = 0; p < par->Last(); ++p) { cw = SingleWidth(pain, par, p); width += cw; @@ -1186,22 +1323,7 @@ void InsetText::computeTextRows(Painter & pain, float x) const wordAscent = max(wordAscent, asc); wordDescent = max(wordDescent, desc); if (par->IsNewline(p)) { - rows.back().asc = wordAscent; - rows.back().desc = wordDescent; - row.pos = p+1; - rows.push_back(row); - SingleHeight(pain, par, p, oasc, odesc); - width = lastWordWidth = 0; - is_first_word_in_row = true; - wordAscent = wordDescent = 0; - continue; - } - Inset const * inset = 0; - if (((p + 1) < par->Last()) && - (par->GetChar(p + 1)==LyXParagraph::META_INSET)) - inset = par->GetInset(p + 1); - if (inset && inset->display()) { - if (!is_first_word_in_row && (width >= (maxWidth - x))) { + if (!is_first_word_in_row && (width >= maxWidth)) { // we have to split also the row above rows.back().asc = oasc; rows.back().desc = odesc; @@ -1212,25 +1334,57 @@ void InsetText::computeTextRows(Painter & pain, float x) const insetWidth = max(insetWidth, owidth); width = lastWordWidth; lastWordWidth = 0; - } else { - oasc = max(oasc, wordAscent); - odesc = max(odesc, wordDescent); } - rows.back().asc = oasc; - rows.back().desc = odesc; + rows.back().asc = wordAscent; + rows.back().desc = wordDescent; row.pos = ++p; rows.push_back(row); - SingleHeight(pain, par, p, asc, desc); - rows.back().asc = asc; - rows.back().desc = desc; - row.pos = nwp = p + 1; - rows.push_back(row); - oasc = odesc = width = lastWordWidth = 0; + SingleHeight(pain, par, p, oasc, odesc); + insetWidth = max(insetWidth, owidth); + width = 0; is_first_word_in_row = true; - wordAscent = wordDescent = 0; + wordAscent = wordDescent = lastWordWidth = 0; + nwp = p; continue; + } + Inset * inset = 0; + if (((p + 1) < par->Last()) && + (par->GetChar(p + 1)==LyXParagraph::META_INSET)) + inset = par->GetInset(p + 1); + if (inset) { + inset->setOwner(const_cast(this)); // is this safe? + if (inset->display()) { + if (!is_first_word_in_row && (width >= maxWidth)) { + // we have to split also the row above + rows.back().asc = oasc; + rows.back().desc = odesc; + row.pos = nwp; + rows.push_back(row); + oasc = wordAscent; + odesc = wordDescent; + insetWidth = max(insetWidth, owidth); + width = lastWordWidth; + lastWordWidth = 0; + } else { + oasc = max(oasc, wordAscent); + odesc = max(odesc, wordDescent); + } + rows.back().asc = oasc; + rows.back().desc = odesc; + row.pos = ++p; + rows.push_back(row); + SingleHeight(pain, par, p, asc, desc); + rows.back().asc = asc; + rows.back().desc = desc; + row.pos = nwp = p + 1; + rows.push_back(row); + oasc = odesc = width = lastWordWidth = 0; + is_first_word_in_row = true; + wordAscent = wordDescent = 0; + continue; + } } else if (par->IsSeparator(p)) { - if (width >= maxWidth - x) { + if (width >= maxWidth) { if (is_first_word_in_row) { rows.back().asc = wordAscent; rows.back().desc = wordDescent; @@ -1261,7 +1415,7 @@ void InsetText::computeTextRows(Painter & pain, float x) const } // if we have some data in the paragraph we have ascent/descent if (p) { - if (width >= (maxWidth - x)) { + if (width >= maxWidth) { // assign upper row rows.back().asc = oasc; rows.back().desc = odesc; @@ -1287,15 +1441,6 @@ void InsetText::computeTextRows(Painter & pain, float x) const for (RowList::size_type i = 1; i < rows.size() - 1; ++i) { maxDescent += rows[i].asc + rows[i].desc + interline_space; } -#if 0 - if (the_locking_inset) { - computeBaselines(top_baseline); - actpos = inset_pos; - resetPos(bv); - inset_x = cx - top_x; - inset_y = cy; - } -#endif } @@ -1308,87 +1453,112 @@ void InsetText::computeBaselines(int baseline) const } } -void InsetText::UpdateLocal(BufferView *bv, bool flag) + +void InsetText::UpdateLocal(BufferView * bv, bool flag) { - HideInsetCursor(bv); if (flag) { computeTextRows(bv->painter(), xpos); computeBaselines(top_baseline); - resetPos(bv); } bv->updateInset(this, flag); - ShowInsetCursor(bv); + if (flag) + resetPos(bv->painter()); + bv->owner()->getToolbar()->combox->select(cursor.par->GetLayout()+1); } -// this is for the simple cut and paste mechanism -// this then should be a global stuff so that cut'n'paste can work in and -// and outside text-insets -static LyXParagraph * simple_cut_buffer = 0; -// static char simple_cut_buffer_textclass = 0; - -// for now here this should be in another Cut&Paste Class! -// -static void DeleteSimpleCutBuffer() -{ - if (!simple_cut_buffer) - return; - LyXParagraph * tmppar; - - while (simple_cut_buffer) { - tmppar = simple_cut_buffer; - simple_cut_buffer = simple_cut_buffer->next; - delete tmppar; - } - simple_cut_buffer = 0; -} bool InsetText::cutSelection() { if (!hasSelection()) return false; - DeleteSimpleCutBuffer(); - - // only within one paragraph - simple_cut_buffer = new LyXParagraph; - LyXParagraph::size_type i = selection_start; - for (; i < selection_end; ++i) { - par->CopyIntoMinibuffer(selection_start); - par->Erase(selection_start); - simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last()); + + CutAndPaste cap; + + LyXParagraph * endpar = par; + int start, end; + if (selection_start_cursor.pos > selection_end_cursor.pos) { + start = selection_end_cursor.pos; + end = selection_start_cursor.pos; + } else { + start = selection_start_cursor.pos; + end = selection_end_cursor.pos; } - return true; + + return cap.cutSelection(par, &endpar, start, end,buffer->params.textclass); } + bool InsetText::copySelection() { if (!hasSelection()) return false; - DeleteSimpleCutBuffer(); - - // only within one paragraph - simple_cut_buffer = new LyXParagraph; - LyXParagraph::size_type i = selection_start; - for (; i < selection_end; ++i) { - par->CopyIntoMinibuffer(i); - simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last()); + + CutAndPaste cap; + + int start, end; + if (selection_start_cursor.pos > selection_end_cursor.pos) { + start = selection_end_cursor.pos; + end = selection_start_cursor.pos; + } else { + start = selection_start_cursor.pos; + end = selection_end_cursor.pos; } - return true; + return cap.copySelection(par, par, start, end, buffer->params.textclass); } + bool InsetText::pasteSelection() { - if (!simple_cut_buffer) + CutAndPaste cap; + + if (cap.nrOfParagraphs() > 1) { + WriteAlert(_("Impossible operation"), + _("Cannot include more than one paragraph!"), + _("Sorry.")); return false; + } + LyXParagraph *endpar; + LyXParagraph *actpar = par; + + return cap.pasteSelection(&actpar, &endpar, cursor.pos, + buffer->params.textclass); +} - LyXParagraph * tmppar = simple_cut_buffer->Clone(); - while (simple_cut_buffer->size()) { - simple_cut_buffer->CutIntoMinibuffer(0); - simple_cut_buffer->Erase(0); - par->InsertFromMinibuffer(actpos); - ++actpos; +bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y, + int button) +{ + if (par->GetChar(cursor.pos) == LyXParagraph::META_INSET) { + UpdatableInset * inset = + static_cast(par->GetInset(cursor.pos)); + LyXFont font = GetFont(par, cursor.pos); + if (x < 0) + x = inset->width(bv->painter(), font); + if (y < 0) + y = inset->descent(bv->painter(), font); + inset_x = cursor.x - top_x + drawTextXOffset; + inset_y = cursor.y + drawTextYOffset; + inset->Edit(bv, x-inset_x, y-inset_y, button); + if (!the_locking_inset) + return false; + UpdateLocal(bv, true); + return true; } - delete simple_cut_buffer; - simple_cut_buffer = tmppar; - return true; + return false; +} + + +int InsetText::getMaxTextWidth(Painter & pain, UpdatableInset const * inset, + int x) const +{ + return getMaxWidth(pain, inset) - x; +} + +void InsetText::SetParagraphData(LyXParagraph *p) +{ + if (par) + delete par; + par = p->Clone(); + par->SetInsetOwner(this); + init_inset = true; }