X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetCollapsable.cpp;h=7a4c99952ddb38d3ce705fcea4d1f2ab36ac94b5;hb=e8c932ff842ced0b26c205ed6983102b6e7e50c2;hp=75c6ef3ab4ab977557d222f4b9a46a5ea9974cb5;hpb=f8f814c3c44dc04804529e75ec87febd39b9b078;p=lyx.git diff --git a/src/insets/InsetCollapsable.cpp b/src/insets/InsetCollapsable.cpp index 75c6ef3ab4..7a4c99952d 100644 --- a/src/insets/InsetCollapsable.cpp +++ b/src/insets/InsetCollapsable.cpp @@ -15,25 +15,15 @@ #include "InsetCollapsable.h" #include "Buffer.h" -#include "BufferParams.h" #include "BufferView.h" #include "Cursor.h" #include "Dimension.h" -#include "DispatchResult.h" -#include "FloatList.h" #include "FuncRequest.h" #include "FuncStatus.h" #include "InsetLayout.h" -#include "InsetList.h" -#include "Language.h" -#include "LaTeXFeatures.h" #include "Lexer.h" #include "MetricsInfo.h" -#include "output_xhtml.h" -#include "paragraph_funcs.h" -#include "ParagraphParameters.h" -#include "sgml.h" -#include "TextClass.h" +#include "OutputParams.h" #include "frontends/FontMetrics.h" #include "frontends/Painter.h" @@ -43,57 +33,61 @@ #include "support/gettext.h" #include "support/lassert.h" #include "support/lstrings.h" +#include "support/RefChanger.h" using namespace std; namespace lyx { -InsetCollapsable::CollapseStatus InsetCollapsable::status(BufferView const & bv) const +InsetCollapsable::InsetCollapsable(Buffer * buf, InsetText::UsePlain ltype) + : InsetText(buf, ltype), status_(Open) { - if (decoration() == InsetLayout::CONGLOMERATE) - return status_; - return auto_open_[&bv] ? Open : status_; + setDrawFrame(true); + setFrameColor(Color_collapsableframe); } -InsetCollapsable::Geometry InsetCollapsable::geometry(BufferView const & bv) const -{ - switch (decoration()) { - case InsetLayout::CLASSIC: - if (status(bv) == Open) - return openinlined_ ? LeftButton : TopButton; - return ButtonOnly; +// The sole purpose of this copy constructor is to make sure +// that the view_ map is not copied and remains empty. +InsetCollapsable::InsetCollapsable(InsetCollapsable const & rhs) + : InsetText(rhs), + status_(rhs.status_), + labelstring_(rhs.labelstring_) +{} - case InsetLayout::MINIMALISTIC: - return status(bv) == Open ? NoButton : ButtonOnly ; - case InsetLayout::CONGLOMERATE: - return status(bv) == Open ? SubLabel : Corners ; +InsetCollapsable::~InsetCollapsable() +{ + map::iterator it = view_.begin(); + map::iterator end = view_.end(); + for (; it != end; ++it) + if (it->second.mouse_hover_) + it->first->clearLastInset(this); +} - case InsetLayout::DEFAULT: - break; // this shouldn't happen - } - // dummy return value to shut down a warning, - // this is dead code. - return NoButton; +InsetCollapsable::CollapseStatus InsetCollapsable::status(BufferView const & bv) const +{ + if (decoration() == InsetLayout::CONGLOMERATE) + return status_; + return view_[&bv].auto_open_ ? Open : status_; } -InsetCollapsable::Geometry InsetCollapsable::geometry() const +InsetCollapsable::Geometry InsetCollapsable::geometry(BufferView const & bv) const { switch (decoration()) { case InsetLayout::CLASSIC: - if (status_ == Open) - return openinlined_ ? LeftButton : TopButton; + if (status(bv) == Open) + return view_[&bv].openinlined_ ? LeftButton : TopButton; return ButtonOnly; case InsetLayout::MINIMALISTIC: - return status_ == Open ? NoButton : ButtonOnly ; + return status(bv) == Open ? NoButton : ButtonOnly ; case InsetLayout::CONGLOMERATE: - return status_ == Open ? SubLabel : Corners ; + return status(bv) == Open ? SubLabel : Corners ; case InsetLayout::DEFAULT: break; // this shouldn't happen @@ -105,42 +99,15 @@ InsetCollapsable::Geometry InsetCollapsable::geometry() const } -InsetCollapsable::InsetCollapsable(Buffer const & buf, InsetText::UsePlain ltype) - : InsetText(buf, ltype), status_(Inset::Open), - openinlined_(false), mouse_hover_(false) -{ - setAutoBreakRows(true); - setDrawFrame(true); - setFrameColor(Color_collapsableframe); -} - - -InsetCollapsable::InsetCollapsable(InsetCollapsable const & rhs) - : InsetText(rhs), - status_(rhs.status_), - labelstring_(rhs.labelstring_), - button_dim(rhs.button_dim), - openinlined_(rhs.openinlined_), - auto_open_(rhs.auto_open_), - // the sole purpose of this copy constructor - mouse_hover_(false) -{ -} - - docstring InsetCollapsable::toolTip(BufferView const & bv, int x, int y) const { - Dimension dim = dimensionCollapsed(bv); + Dimension const dim = dimensionCollapsed(bv); if (geometry(bv) == NoButton) return translateIfPossible(getLayout().labelstring()); if (x > xo(bv) + dim.wid || y > yo(bv) + dim.des || isOpen(bv)) return docstring(); - OutputParams rp(&buffer().params().encoding()); - odocstringstream ods; - InsetText::plaintext(ods, rp); - docstring const content_tip = ods.str(); - return support::wrapParas(content_tip, 4); + return toolTipText(); } @@ -156,7 +123,7 @@ void InsetCollapsable::write(ostream & os) const break; } os << "\n"; - text().write(buffer(), os); + text().write(os); } @@ -177,7 +144,9 @@ void InsetCollapsable::read(Lexer & lex) Dimension InsetCollapsable::dimensionCollapsed(BufferView const & bv) const { Dimension dim; - theFontMetrics(getLayout().labelfont()).buttonText( + FontInfo labelfont(getLabelfont()); + labelfont.realize(sane_font); + theFontMetrics(labelfont).buttonText( buttonLabel(bv), dim.wid, dim.asc, dim.des); return dim; } @@ -185,10 +154,10 @@ Dimension InsetCollapsable::dimensionCollapsed(BufferView const & bv) const void InsetCollapsable::metrics(MetricsInfo & mi, Dimension & dim) const { - auto_open_[mi.base.bv] = mi.base.bv->cursor().isInside(this); + view_[mi.base.bv].auto_open_ = mi.base.bv->cursor().isInside(this); FontInfo tmpfont = mi.base.font; - mi.base.font = getLayout().font(); + mi.base.font = getFont(); mi.base.font.realize(tmpfont); BufferView const & bv = *mi.base.bv; @@ -205,7 +174,7 @@ void InsetCollapsable::metrics(MetricsInfo & mi, Dimension & dim) const case SubLabel: { InsetText::metrics(mi, dim); // consider width of the inset label - FontInfo font(getLayout().labelfont()); + FontInfo font(getLabelfont()); font.realize(sane_font); font.decSize(); font.decSize(); @@ -219,13 +188,17 @@ void InsetCollapsable::metrics(MetricsInfo & mi, Dimension & dim) const case TopButton: case LeftButton: case ButtonOnly: + if (hasFixedWidth()){ + int const mindim = view_[&bv].button_dim_.x2 - view_[&bv].button_dim_.x1; + if (mi.base.textwidth < mindim) + mi.base.textwidth = mindim; + } dim = dimensionCollapsed(bv); - if (geometry(bv) == TopButton - || geometry(bv) == LeftButton) { + if (geometry(bv) == TopButton || geometry(bv) == LeftButton) { Dimension textdim; InsetText::metrics(mi, textdim); - openinlined_ = (textdim.wid + dim.wid) < mi.base.textwidth; - if (openinlined_) { + view_[&bv].openinlined_ = (textdim.wid + dim.wid) < mi.base.textwidth; + if (view_[&bv].openinlined_) { // Correct for button width. dim.wid += textdim.wid; dim.des = max(dim.des - textdim.asc + dim.asc, textdim.des); @@ -242,9 +215,10 @@ void InsetCollapsable::metrics(MetricsInfo & mi, Dimension & dim) const } -bool InsetCollapsable::setMouseHover(bool mouse_hover) +bool InsetCollapsable::setMouseHover(BufferView const * bv, bool mouse_hover) + const { - mouse_hover_ = mouse_hover; + view_[bv].mouse_hover_ = mouse_hover; return true; } @@ -253,48 +227,59 @@ void InsetCollapsable::draw(PainterInfo & pi, int x, int y) const { BufferView const & bv = *pi.base.bv; - auto_open_[&bv] = bv.cursor().isInside(this); + view_[&bv].auto_open_ = bv.cursor().isInside(this); - FontInfo tmpfont = pi.base.font; - pi.base.font = getLayout().font(); - pi.base.font.realize(tmpfont); + Changer dummy = pi.base.font.change(getFont(), true); // Draw button first -- top, left or only Dimension dimc = dimensionCollapsed(bv); - if (geometry(*pi.base.bv) == TopButton || - geometry(*pi.base.bv) == LeftButton || - geometry(*pi.base.bv) == ButtonOnly) { - button_dim.x1 = x + 0; - button_dim.x2 = x + dimc.width(); - button_dim.y1 = y - dimc.asc; - button_dim.y2 = y + dimc.des; + if (geometry(bv) == TopButton || + geometry(bv) == LeftButton || + geometry(bv) == ButtonOnly) { + view_[&bv].button_dim_.x1 = x + 0; + view_[&bv].button_dim_.x2 = x + dimc.width(); + view_[&bv].button_dim_.y1 = y - dimc.asc; + view_[&bv].button_dim_.y2 = y + dimc.des; - FontInfo labelfont = getLayout().labelfont(); + FontInfo labelfont = getLabelfont(); labelfont.setColor(labelColor()); + labelfont.realize(pi.base.font); pi.pain.buttonText(x, y, buttonLabel(bv), labelfont, - mouse_hover_); + view_[&bv].mouse_hover_); + // Draw the change tracking cue on the label, unless RowPainter already + // takes care of it. + if (canPaintChange(bv)) + pi.change_.paintCue(pi, x, y, x + dimc.width(), labelfont); } else { - button_dim.x1 = 0; - button_dim.y1 = 0; - button_dim.x2 = 0; - button_dim.y2 = 0; + view_[&bv].button_dim_.x1 = 0; + view_[&bv].button_dim_.y1 = 0; + view_[&bv].button_dim_.x2 = 0; + view_[&bv].button_dim_.y2 = 0; } - Dimension const textdim = InsetText::dimension(bv); + Dimension const textdim = dimensionHelper(bv); int const baseline = y; int textx, texty; - switch (geometry(bv)) { + Geometry g = geometry(bv); + switch (g) { case LeftButton: - textx = x + dimc.width(); - texty = baseline; - InsetText::draw(pi, textx, texty); - break; - case TopButton: - textx = x; - texty = baseline + dimc.des + textdim.asc; + case TopButton: { + if (g == LeftButton) { + textx = x + dimc.width(); + texty = baseline; + } else { + textx = x; + texty = baseline + dimc.des + textdim.asc; + } + // Do not draw the cue for INSERTED -- it is already in the button and + // that's enough. + Changer dummy = (pi.change_.type == Change::INSERTED) + ? make_change(pi.change_, Change()) + : Changer(); InsetText::draw(pi, textx, texty); break; + } case ButtonOnly: break; case NoButton: @@ -306,67 +291,71 @@ void InsetCollapsable::draw(PainterInfo & pi, int x, int y) const case Corners: textx = x; texty = baseline; - const_cast(this)->setDrawFrame(false); - InsetText::draw(pi, textx, texty); - const_cast(this)->setDrawFrame(true); + { // We will take care of the frame and the change tracking cue + // ourselves, below. + Changer dummy = make_change(pi.change_, Change()); + const_cast(this)->setDrawFrame(false); + InsetText::draw(pi, textx, texty); + const_cast(this)->setDrawFrame(true); + } int desc = textdim.descent(); - if (geometry(bv) == Corners) + if (g == Corners) desc -= 3; + // Colour the frame according to the change type. (Like for tables.) + Color colour = pi.change_.changed() ? pi.change_.color() + : Color_foreground; const int xx1 = x + TEXT_TO_INSET_OFFSET - 1; const int xx2 = x + textdim.wid - TEXT_TO_INSET_OFFSET + 1; - pi.pain.line(xx1, y + desc - 4, - xx1, y + desc, - labelColor()); + pi.pain.line(xx1, y + desc - 4, + xx1, y + desc, colour); if (status_ == Open) - pi.pain.line(xx1, y + desc, - xx2, y + desc, - labelColor()); + pi.pain.line(xx1, y + desc, + xx2, y + desc, colour); else { // Make status_ value visible: pi.pain.line(xx1, y + desc, - xx1 + 4, y + desc, - labelColor()); + xx1 + 4, y + desc, colour); pi.pain.line(xx2 - 4, y + desc, - xx2, y + desc, - labelColor()); + xx2, y + desc, colour); } - pi.pain.line(x + textdim.wid - 3, y + desc, x + textdim.wid - 3, - y + desc - 4, labelColor()); + pi.pain.line(x + textdim.wid - 3, y + desc, x + textdim.wid - 3, + y + desc - 4, colour); // the label below the text. Can be toggled. - if (geometry(bv) == SubLabel) { - FontInfo font(getLayout().labelfont()); + if (g == SubLabel) { + FontInfo font(getLabelfont()); + if (pi.change_.changed()) + font.setPaintColor(colour); font.realize(sane_font); font.decSize(); font.decSize(); int w = 0; int a = 0; int d = 0; + Color const col = pi.full_repaint ? Color_none : pi.backgroundColor(this); theFontMetrics(font).rectText(buttonLabel(bv), w, a, d); int const ww = max(textdim.wid, w); pi.pain.rectText(x + (ww - w) / 2, y + desc + a, - buttonLabel(bv), font, Color_none, Color_none); - desc += d; + buttonLabel(bv), font, col, Color_none); } + int const y1 = y - textdim.asc + 3; // a visual cue when the cursor is inside the inset Cursor const & cur = bv.cursor(); if (cur.isInside(this)) { - y -= textdim.asc; - y += 3; - pi.pain.line(xx1, y + 4, xx1, y, labelColor()); - pi.pain.line(xx1 + 4, y, xx1, y, labelColor()); - pi.pain.line(xx2, y + 4, xx2, y, - labelColor()); - pi.pain.line(xx2 - 4, y, xx2, y, - labelColor()); + pi.pain.line(xx1, y1 + 4, xx1, y1, colour); + pi.pain.line(xx1 + 4, y1, xx1, y1, colour); + pi.pain.line(xx2, y1 + 4, xx2, y1, colour); + pi.pain.line(xx2 - 4, y1, xx2, y1, colour); } + // Strike through the inset if deleted and not already handled by + // RowPainter. + if (pi.change_.deleted() && canPaintChange(bv)) + pi.change_.paintCue(pi, xx1, y1, xx2, y + desc); break; } - - pi.base.font = tmpfont; } @@ -375,10 +364,9 @@ void InsetCollapsable::cursorPos(BufferView const & bv, { if (geometry(bv) == ButtonOnly) status_ = Open; - LASSERT(geometry(bv) != ButtonOnly, /**/); InsetText::cursorPos(bv, sl, boundary, x, y); - Dimension const textdim = InsetText::dimension(bv); + Dimension const textdim = dimensionHelper(bv); switch (geometry(bv)) { case LeftButton: @@ -402,19 +390,25 @@ void InsetCollapsable::cursorPos(BufferView const & bv, bool InsetCollapsable::editable() const { - return geometry() != ButtonOnly; + switch (decoration()) { + case InsetLayout::CLASSIC: + case InsetLayout::MINIMALISTIC: + return status_ == Open; + default: + return true; + } } -bool InsetCollapsable::descendable() const +bool InsetCollapsable::descendable(BufferView const & bv) const { - return geometry() != ButtonOnly; + return geometry(bv) != ButtonOnly; } -bool InsetCollapsable::hitButton(FuncRequest const & cmd) const +bool InsetCollapsable::clickable(BufferView const & bv, int x, int y) const { - return button_dim.contains(cmd.x, cmd.y); + return view_[&bv].button_dim_.contains(x, y); } @@ -451,8 +445,8 @@ Inset * InsetCollapsable::editXY(Cursor & cur, int x, int y) { //lyxerr << "InsetCollapsable: edit xy" << endl; if (geometry(cur.bv()) == ButtonOnly - || (button_dim.contains(x, y) - && geometry(cur.bv()) != NoButton)) + || (view_[&cur.bv()].button_dim_.contains(x, y) + && geometry(cur.bv()) != NoButton)) return this; cur.push(*this); return InsetText::editXY(cur, x, y); @@ -464,9 +458,11 @@ void InsetCollapsable::doDispatch(Cursor & cur, FuncRequest & cmd) //lyxerr << "InsetCollapsable::doDispatch (begin): cmd: " << cmd // << " cur: " << cur << " bvcur: " << cur.bv().cursor() << endl; - switch (cmd.action) { + bool const hitButton = clickable(cur.bv(), cmd.x(), cmd.y()); + + switch (cmd.action()) { case LFUN_MOUSE_PRESS: - if (hitButton(cmd)) { + if (hitButton) { switch (cmd.button()) { case mouse_button::button1: case mouse_button::button3: @@ -479,7 +475,7 @@ void InsetCollapsable::doDispatch(Cursor & cur, FuncRequest & cmd) case mouse_button::button4: case mouse_button::button5: // Nothing to do. - cur.noUpdate(); + cur.noScreenUpdate(); break; } } else if (geometry(cur.bv()) != ButtonOnly) @@ -491,8 +487,8 @@ void InsetCollapsable::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_MOUSE_MOTION: case LFUN_MOUSE_DOUBLE: case LFUN_MOUSE_TRIPLE: - if (hitButton(cmd)) - cur.noUpdate(); + if (hitButton) + cur.noScreenUpdate(); else if (geometry(cur.bv()) != ButtonOnly) InsetText::doDispatch(cur, cmd); else @@ -500,17 +496,17 @@ void InsetCollapsable::doDispatch(Cursor & cur, FuncRequest & cmd) break; case LFUN_MOUSE_RELEASE: - if (!hitButton(cmd)) { + if (!hitButton) { // The mouse click has to be within the inset! if (geometry(cur.bv()) != ButtonOnly) InsetText::doDispatch(cur, cmd); else - cur.undispatched(); + cur.undispatched(); break; } if (cmd.button() != mouse_button::button1) { // Nothing to do. - cur.noUpdate(); + cur.noScreenUpdate(); break; } // if we are selecting, we do not want to @@ -520,7 +516,7 @@ void InsetCollapsable::doDispatch(Cursor & cur, FuncRequest & cmd) // Left button is clicked, the user asks to // toggle the inset visual state. cur.dispatched(); - cur.updateFlags(Update::Force | Update::FitCursor); + cur.screenUpdateFlags(Update::Force | Update::FitCursor); if (geometry(cur.bv()) == ButtonOnly) { setStatus(cur, Open); edit(cur, true); @@ -536,98 +532,15 @@ void InsetCollapsable::doDispatch(Cursor & cur, FuncRequest & cmd) else if (cmd.argument() == "close") setStatus(cur, Collapsed); else if (cmd.argument() == "toggle" || cmd.argument().empty()) - if (status_ == Open) { + if (status_ == Open) setStatus(cur, Collapsed); - if (geometry(cur.bv()) == ButtonOnly) - cur.top().forwardPos(); - } else + else setStatus(cur, Open); else // if assign or anything else cur.undispatched(); cur.dispatched(); break; - case LFUN_TAB_INSERT: { - bool const multi_par_selection = cur.selection() && - cur.selBegin().pit() != cur.selEnd().pit(); - if (multi_par_selection) { - // If there is a multi-paragraph selection, a tab is inserted - // at the beginning of each paragraph. - cur.recordUndoSelection(); - pit_type const pit_end = cur.selEnd().pit(); - for (pit_type pit = cur.selBegin().pit(); pit <= pit_end; pit++) { - paragraphs()[pit].insertChar(0, '\t', - buffer().params().trackChanges); - // Update the selection pos to make sure the selection does not - // change as the inserted tab will increase the logical pos. - if (cur.anchor_.pit() == pit) - cur.anchor_.forwardPos(); - if (cur.pit() == pit) - cur.forwardPos(); - } - cur.finishUndo(); - } else { - // Maybe we shouldn't allow tabs within a line, because they - // are not (yet) aligned as one might do expect. - FuncRequest cmd(LFUN_SELF_INSERT, from_ascii("\t")); - dispatch(cur, cmd); - } - break; - } - - case LFUN_TAB_DELETE: - if (cur.selection()) { - // If there is a selection, a tab (if present) is removed from - // the beginning of each paragraph. - cur.recordUndoSelection(); - pit_type const pit_end = cur.selEnd().pit(); - for (pit_type pit = cur.selBegin().pit(); pit <= pit_end; pit++) { - Paragraph & par = paragraphs()[pit]; - if (par.getChar(0) == '\t') { - if (cur.pit() == pit) - cur.posBackward(); - if (cur.anchor_.pit() == pit && cur.anchor_.pos() > 0 ) - cur.anchor_.backwardPos(); - - par.eraseChar(0, buffer().params().trackChanges); - } else - // If no tab was present, try to remove up to four spaces. - for (int n_spaces = 0; - par.getChar(0) == ' ' && n_spaces < 4; ++n_spaces) { - if (cur.pit() == pit) - cur.posBackward(); - if (cur.anchor_.pit() == pit && cur.anchor_.pos() > 0 ) - cur.anchor_.backwardPos(); - - par.eraseChar(0, buffer().params().trackChanges); - } - } - cur.finishUndo(); - } else { - // If there is no selection, try to remove a tab or some spaces - // before the position of the cursor. - Paragraph & par = paragraphs()[cur.pit()]; - pos_type const pos = cur.pos(); - - if (pos == 0) - break; - - char_type const c = par.getChar(pos - 1); - cur.recordUndo(); - if (c == '\t') { - cur.posBackward(); - par.eraseChar(cur.pos(), buffer().params().trackChanges); - } else - for (int n_spaces = 0; cur.pos() > 0 - && par.getChar(cur.pos() - 1) == ' ' && n_spaces < 4; - ++n_spaces) { - cur.posBackward(); - par.eraseChar(cur.pos(), buffer().params().trackChanges); - } - cur.finishUndo(); - } - break; - default: InsetText::doDispatch(cur, cmd); break; @@ -638,97 +551,7 @@ void InsetCollapsable::doDispatch(Cursor & cur, FuncRequest & cmd) bool InsetCollapsable::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & flag) const { - switch (cmd.action) { - // FIXME At present, these are being enabled and disabled according to - // whether PASSTHRU has been set in the InsetLayout. This makes some - // sense, but there are other checks that should really be done. E.g., - // one should not be able to inset IndexPrint inside an optional argument!! - case LFUN_ACCENT_ACUTE: - case LFUN_ACCENT_BREVE: - case LFUN_ACCENT_CARON: - case LFUN_ACCENT_CEDILLA: - case LFUN_ACCENT_CIRCLE: - case LFUN_ACCENT_CIRCUMFLEX: - case LFUN_ACCENT_DOT: - case LFUN_ACCENT_GRAVE: - case LFUN_ACCENT_HUNGARIAN_UMLAUT: - case LFUN_ACCENT_MACRON: - case LFUN_ACCENT_OGONEK: - case LFUN_ACCENT_TIE: - case LFUN_ACCENT_TILDE: - case LFUN_ACCENT_UMLAUT: - case LFUN_ACCENT_UNDERBAR: - case LFUN_ACCENT_UNDERDOT: - case LFUN_APPENDIX: - case LFUN_BOX_INSERT: - case LFUN_BRANCH_INSERT: - case LFUN_CAPTION_INSERT: - case LFUN_DEPTH_DECREMENT: - case LFUN_DEPTH_INCREMENT: - case LFUN_ERT_INSERT: - case LFUN_FILE_INSERT: - case LFUN_FLEX_INSERT: - case LFUN_FLOAT_INSERT: - case LFUN_FLOAT_LIST_INSERT: - case LFUN_FLOAT_WIDE_INSERT: - case LFUN_FONT_BOLD: - case LFUN_FONT_BOLDSYMBOL: - case LFUN_FONT_TYPEWRITER: - case LFUN_FONT_DEFAULT: - case LFUN_FONT_EMPH: - case LFUN_FONT_NOUN: - case LFUN_FONT_ROMAN: - case LFUN_FONT_SANS: - case LFUN_FONT_FRAK: - case LFUN_FONT_ITAL: - case LFUN_FONT_SIZE: - case LFUN_FONT_STATE: - case LFUN_FONT_UNDERLINE: - case LFUN_FONT_STRIKEOUT: - case LFUN_FONT_UULINE: - case LFUN_FONT_UWAVE: - case LFUN_FOOTNOTE_INSERT: - case LFUN_HYPERLINK_INSERT: - case LFUN_INDEX_INSERT: - case LFUN_INDEX_PRINT: - case LFUN_INSET_INSERT: - case LFUN_LABEL_GOTO: - case LFUN_LABEL_INSERT: - case LFUN_LAYOUT_TABULAR: - case LFUN_LINE_INSERT: - case LFUN_MARGINALNOTE_INSERT: - case LFUN_MATH_DISPLAY: - case LFUN_MATH_INSERT: - case LFUN_MATH_AMS_MATRIX: - case LFUN_MATH_MATRIX: - case LFUN_MATH_MODE: - case LFUN_MENU_OPEN: - case LFUN_NEWLINE_INSERT: - case LFUN_NEWPAGE_INSERT: - case LFUN_NOACTION: - case LFUN_NOMENCL_INSERT: - case LFUN_NOMENCL_PRINT: - case LFUN_NOTE_INSERT: - case LFUN_NOTE_NEXT: - case LFUN_OPTIONAL_INSERT: - case LFUN_PHANTOM_INSERT: - case LFUN_REFERENCE_NEXT: - case LFUN_SERVER_GOTO_FILE_ROW: - case LFUN_SERVER_NOTIFY: - case LFUN_SERVER_SET_XY: - case LFUN_SPACE_INSERT: - case LFUN_SPECIALCHAR_INSERT: - case LFUN_TABULAR_INSERT: - case LFUN_TEXTSTYLE_APPLY: - case LFUN_TEXTSTYLE_UPDATE: - case LFUN_TOC_INSERT: - case LFUN_WRAP_INSERT: - if (getLayout().isPassThru()) { - flag.setEnabled(false); - return true; - } - return InsetText::getStatus(cur, cmd, flag); - + switch (cmd.action()) { case LFUN_INSET_TOGGLE: if (cmd.argument() == "open") flag.setEnabled(status_ != Open); @@ -741,22 +564,6 @@ bool InsetCollapsable::getStatus(Cursor & cur, FuncRequest const & cmd, flag.setEnabled(false); return true; - case LFUN_LANGUAGE: - flag.setEnabled(!getLayout().isForceLtr()); - return InsetText::getStatus(cur, cmd, flag); - - case LFUN_BREAK_PARAGRAPH: - flag.setEnabled(getLayout().isMultiPar()); - return true; - - case LFUN_TAB_INSERT: - case LFUN_TAB_DELETE: - if (getLayout().isPassThru()) { - flag.setEnabled(true); - return true; - } - return InsetText::getStatus(cur, cmd, flag); - default: return InsetText::getStatus(cur, cmd, flag); } @@ -769,24 +576,23 @@ void InsetCollapsable::setLabel(docstring const & l) } -void InsetCollapsable::setStatus(Cursor & cur, CollapseStatus status) +docstring const InsetCollapsable::buttonLabel(BufferView const & bv) const { - status_ = status; - setButtonLabel(); - if (status_ == Collapsed) { - cur.leaveInset(*this); - mouse_hover_ = false; - } + InsetLayout const & il = getLayout(); + docstring const label = labelstring_.empty() ? + translateIfPossible(il.labelstring()) : labelstring_; + if (!il.contentaslabel() || geometry(bv) != ButtonOnly) + return label; + return getNewLabel(label); } -docstring InsetCollapsable::floatName(string const & type) const +void InsetCollapsable::setStatus(Cursor & cur, CollapseStatus status) { - BufferParams const & bp = buffer().params(); - FloatList const & floats = bp.documentClass().floats(); - FloatList::const_iterator it = floats[type]; - // FIXME UNICODE - return (it == floats.end()) ? from_ascii(type) : bp.B_(it->second.name()); + status_ = status; + setButtonLabel(); + if (status_ == Collapsed) + cur.leaveInset(*this); } @@ -797,133 +603,53 @@ InsetLayout::InsetDecoration InsetCollapsable::decoration() const } -int InsetCollapsable::latex(odocstream & os, - OutputParams const & runparams) const -{ - // This implements the standard way of handling the LaTeX output of - // a collapsable inset, either a command or an environment. Standard - // collapsable insets should not redefine this, non-standard ones may - // call this. - if (!getLayout().latexname().empty()) { - if (getLayout().latextype() == InsetLayout::COMMAND) { - // FIXME UNICODE - if (runparams.moving_arg) - os << "\\protect"; - os << '\\' << from_utf8(getLayout().latexname()); - if (!getLayout().latexparam().empty()) - os << from_utf8(getLayout().latexparam()); - os << '{'; - } else if (getLayout().latextype() == InsetLayout::ENVIRONMENT) { - os << "%\n\\begin{" << from_utf8(getLayout().latexname()) << "}\n"; - if (!getLayout().latexparam().empty()) - os << from_utf8(getLayout().latexparam()); - } - } - OutputParams rp = runparams; - if (getLayout().isPassThru()) - rp.verbatim = true; - if (getLayout().isNeedProtect()) - rp.moving_arg = true; - int i = InsetText::latex(os, rp); - if (!getLayout().latexname().empty()) { - if (getLayout().latextype() == InsetLayout::COMMAND) { - os << "}"; - } else if (getLayout().latextype() == InsetLayout::ENVIRONMENT) { - os << "\n\\end{" << from_utf8(getLayout().latexname()) << "}\n"; - i += 4; - } - } - return i; -} - - -// FIXME It seems as if it ought to be possible to do this more simply, -// maybe by calling InsetText::docbook() in the middle there. -int InsetCollapsable::docbook(odocstream & os, OutputParams const & runparams) const -{ - ParagraphList::const_iterator const beg = paragraphs().begin(); - ParagraphList::const_iterator par = paragraphs().begin(); - ParagraphList::const_iterator const end = paragraphs().end(); - - if (!undefined()) - sgml::openTag(os, getLayout().latexname(), - par->getID(buffer(), runparams) + getLayout().latexparam()); - - for (; par != end; ++par) { - par->simpleDocBookOnePar(buffer(), os, runparams, - outerFont(distance(beg, par), - paragraphs())); - } - - if (!undefined()) - sgml::closeTag(os, getLayout().latexname()); - - return 0; -} - - -docstring InsetCollapsable::xhtml(odocstream & os, OutputParams const & runparams) const +string InsetCollapsable::contextMenu(BufferView const & bv, int x, + int y) const { - InsetLayout const & il = getLayout(); - if (undefined()) - return InsetText::xhtml(os, runparams); - - bool const opened = html::openTag(os, il.htmltag(), il.htmlattr()); - if (!il.counter().empty()) { - BufferParams const & bp = buffer().masterBuffer()->params(); - Counters & cntrs = bp.documentClass().counters(); - cntrs.step(il.counter()); - // FIXME: translate to paragraph language - if (!il.htmllabel().empty()) - os << cntrs.counterLabel(from_utf8(il.htmllabel()), bp.language->code()); - } - bool innertag_opened = false; - if (!il.htmlinnertag().empty()) - innertag_opened = html::openTag(os, il.htmlinnertag(), il.htmlinnerattr()); - docstring deferred = InsetText::xhtml(os, runparams); - if (innertag_opened) - html::closeTag(os, il.htmlinnertag()); - if (opened) - html::closeTag(os, il.htmltag()); - return deferred; -} + string context_menu = contextMenuName(); + string const it_context_menu = InsetText::contextMenuName(); + if (decoration() == InsetLayout::CONGLOMERATE) + return context_menu + ";" + it_context_menu; + string const ic_context_menu = InsetCollapsable::contextMenuName(); + if (ic_context_menu != context_menu) + context_menu += ";" + ic_context_menu; -void InsetCollapsable::validate(LaTeXFeatures & features) const -{ - features.useInsetLayout(getLayout()); - InsetText::validate(features); -} + if (geometry(bv) == NoButton) + return context_menu + ";" + it_context_menu; + Dimension dim = dimensionCollapsed(bv); + if (x < xo(bv) + dim.wid && y < yo(bv) + dim.des) + return context_menu; -bool InsetCollapsable::undefined() const -{ - docstring const & n = getLayout().name(); - return n.empty() || n == DocumentClass::plainInsetLayout().name(); + return it_context_menu; } -docstring InsetCollapsable::contextMenu(BufferView const & bv, int x, - int y) const +string InsetCollapsable::contextMenuName() const { if (decoration() == InsetLayout::CONGLOMERATE) - return from_ascii("context-conglomerate"); - - if (geometry(bv) == NoButton) - return from_ascii("context-collapsable"); - - Dimension dim = dimensionCollapsed(bv); - if (x < xo(bv) + dim.wid && y < yo(bv) + dim.des) - return from_ascii("context-collapsable"); - - return InsetText::contextMenu(bv, x, y); + return "context-conglomerate"; + else + return "context-collapsable"; } -void InsetCollapsable::tocString(odocstream & os) const + +bool InsetCollapsable::canPaintChange(BufferView const & bv) const { - if (!getLayout().isInToc()) - return; - os << text().asString(0, 1, AS_STR_LABEL | AS_STR_INSETS); + // return false to let RowPainter draw the change tracking cue consistently + // with the surrounding text, when the inset is inline: for buttons, for + // non-allowMultiPar insets. + switch (geometry(bv)) { + case Corners: + case SubLabel: + return allowMultiPar(); + case ButtonOnly: + return false; + default: + break; + } + return true; }