X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2Finsettext.C;h=e0b8f1f5b35ef77a7f2bdc85ec5bb3384fbc66f5;hb=3c8aba3b556871fb1100a2f98cd93d5d4e3f70c9;hp=4ced0622b676bdbf453dcd0bc9472940743b67ba;hpb=fa492d6bf09db7f1c278687e0000ad1c4833af3d;p=lyx.git diff --git a/src/insets/insettext.C b/src/insets/insettext.C index 4ced0622b6..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 @@ -52,40 +49,59 @@ using std::max; #include "Painter.h" #include "lyx_gui_misc.h" #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) { par = new LyXParagraph(); - the_locking_inset = 0; - buffer = buf; - cursor_visible = false; - maxWidth = old_x = -1; - actpos = selection_start = selection_end = 0; - interline_space = 1; - no_selection = false; - init_inset = true; - maxAscent = maxDescent = insetWidth = widthOffset = 0; - autoBreakRows = false; - xpos = 0.0; + init(buf); } InsetText::InsetText(InsetText const & ins, Buffer * buf) { - par = new LyXParagraph(ins.par); + par = 0; + init(buf, &ins); + autoBreakRows = ins.autoBreakRows; +} + + +void InsetText::init(Buffer * buf, InsetText const * ins) +{ 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; } @@ -127,6 +143,7 @@ void InsetText::Read(LyXLex & lex) delete par; par = new LyXParagraph; + par->SetInsetOwner(this); while (lex.IsOK()) { lex.nextToken(); @@ -156,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); } @@ -168,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); } @@ -180,6 +199,7 @@ int InsetText::width(Painter & pain, LyXFont const &) const { if (init_inset) { computeTextRows(pain, xpos); + resetPos(pain); init_inset = false; } return insetWidth; @@ -190,24 +210,28 @@ void InsetText::draw(Painter & pain, LyXFont const & f, int baseline, float & x) const { xpos = x; - computeTextRows(pain, x); UpdatableInset::draw(pain, f, baseline, x); - bool do_reset_pos = (x != top_x) || (baseline != top_baseline); - 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); drawRowText(pain, rows[r].pos, rows[r + 1].pos, rows[r].baseline, x); } x += insetWidth; - if (!the_locking_inset && do_reset_pos) { -// HideInsetCursor(bv); -// resetPos(bv); -// ShowInsetCursor(bv); - } } @@ -218,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; @@ -238,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) @@ -268,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]; @@ -306,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); } } } @@ -320,33 +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; @@ -357,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); } @@ -367,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; } @@ -454,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; @@ -488,149 +590,252 @@ InsetText::LocalDispatch(BufferView * bv, switch (action) { // Normal chars case -1: - par->InsertChar(actpos,arg[0]); - par->SetFont(actpos,real_current_font); + 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); + cutSelection(); + 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); - ++actpos; - selection_start = selection_end = actpos; - resetPos(bv); 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: - result= DISPATCH_RESULT(moveRight(bv)); + bv->text->FinishUndo(); + 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: - result= DISPATCH_RESULT(moveLeft(bv)); - if (hasSelection()) { - selection_start = selection_end = actpos; - UpdateLocal(bv, false); - } else { - selection_start = selection_end = actpos; - } - break; + bv->text->FinishUndo(); + result= moveLeft(bv); + if (hasSelection()) { + selection_start_cursor = selection_end_cursor = cursor; + UpdateLocal(bv, false); + } else { + selection_start_cursor = selection_end_cursor = cursor; + } + break; case LFUN_DOWNSEL: - moveDown(bv, false); - selection_end = actpos; + bv->text->FinishUndo(); + moveDown(bv); + selection_end_cursor = cursor; UpdateLocal(bv, false); break; case LFUN_DOWN: - result= DISPATCH_RESULT(moveDown(bv)); + bv->text->FinishUndo(); + 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: - moveUp(bv, false); - selection_end = actpos; + bv->text->FinishUndo(); + moveUp(bv); + selection_end_cursor = cursor; UpdateLocal(bv, false); break; case LFUN_UP: - result= DISPATCH_RESULT(moveUp(bv)); + bv->text->FinishUndo(); + 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: - if (Delete()) { // we need update - selection_start = selection_end = actpos; + { + 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); + 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_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); + } + } + 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 + cursor = selection_end_cursor = selection_start_cursor; + UpdateLocal(bv, true); + } else if (hasSelection()) { + 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_cursor = selection_end_cursor = cursor; + UpdateLocal(bv, true); + } else if (hasSelection()) { + 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); + if (pasteSelection()) { + selection_start_cursor = selection_end_cursor = cursor; + UpdateLocal(bv, true); + } + } + resetPos(bv->painter()); + break; case LFUN_HOME: - for(; actpos > rows[actrow].pos; --actpos) - cx -= SingleWidth(bv->getPainter(), par, actpos); - cx -= SingleWidth(bv->getPainter(), par, actpos); + bv->text->FinishUndo(); + 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: { + bv->text->FinishUndo(); 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 + 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: - par->InsertChar(actpos,LyXParagraph::META_NEWLINE); - par->SetFont(actpos,real_current_font); + 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(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(); } @@ -643,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) @@ -658,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); } @@ -666,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; @@ -677,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; } @@ -757,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, @@ -769,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; } @@ -779,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()); } @@ -791,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; } } @@ -820,172 +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) { - 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 mathod 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; } @@ -1002,13 +1207,14 @@ 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); // Update current font - real_current_font.update(font, toggleall); + real_current_font.update(font, bv->buffer()->params.language_info, + toggleall); // Reduce to implicit settings current_font = real_current_font; @@ -1019,17 +1225,17 @@ 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) { newfont = GetFont(par,s_start); - newfont.update(font, toggleall); + newfont.update(font, bv->buffer()->params.language_info, toggleall); SetCharFont(s_start, newfont); ++s_start; } @@ -1106,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; @@ -1118,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; @@ -1144,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; @@ -1193,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; @@ -1205,8 +1427,6 @@ void InsetText::computeTextRows(Painter & pain, float x) const width -= lastWordWidth; } else { // assign last row data -// width = lastWordWidth; -// lastWordWidth = 0; rows.back().asc = max(oasc, wordAscent); rows.back().desc = max(odesc, wordDescent); } @@ -1221,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 } @@ -1242,8 +1453,112 @@ void InsetText::computeBaselines(int baseline) const } } -void InsetText::UpdateLocal(BufferView *bv, bool flag) + +void InsetText::UpdateLocal(BufferView * bv, bool flag) { - init_inset = flag; + if (flag) { + computeTextRows(bv->painter(), xpos); + computeBaselines(top_baseline); + } bv->updateInset(this, flag); + if (flag) + resetPos(bv->painter()); + bv->owner()->getToolbar()->combox->select(cursor.par->GetLayout()+1); +} + + +bool InsetText::cutSelection() +{ + if (!hasSelection()) + return false; + + 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 cap.cutSelection(par, &endpar, start, end,buffer->params.textclass); +} + + +bool InsetText::copySelection() +{ + if (!hasSelection()) + return false; + + 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 cap.copySelection(par, par, start, end, buffer->params.textclass); +} + + +bool InsetText::pasteSelection() +{ + 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); +} + + +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; + } + 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; }