X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetCollapsable.cpp;h=fa9f01056ab685e00ae67280e2faafa1541dec5f;hb=239b9919ffe28338d789e6dc9122228f77ab77a7;hp=70e21e6e94bb20001aae8071dbdde989797bc297;hpb=f038c80e3379eab9e16b3680e98741bb6304491c;p=lyx.git diff --git a/src/insets/InsetCollapsable.cpp b/src/insets/InsetCollapsable.cpp index 70e21e6e94..fa9f01056a 100644 --- a/src/insets/InsetCollapsable.cpp +++ b/src/insets/InsetCollapsable.cpp @@ -4,8 +4,8 @@ * Licence details can be found in the file COPYING. * * \author Alejandro Aguilar Sierra - * \author Jürgen Vigna - * \author Lars Gullik Bjønnes + * \author Jürgen Vigna + * \author Lars Gullik Bjønnes * * Full author contact details are available in file CREDITS. */ @@ -15,56 +15,83 @@ #include "InsetCollapsable.h" #include "Buffer.h" -#include "BufferParams.h" #include "BufferView.h" #include "Cursor.h" -#include "debug.h" -#include "DispatchResult.h" -#include "FloatList.h" +#include "Dimension.h" +#include "FuncRequest.h" #include "FuncStatus.h" -#include "gettext.h" -#include "Language.h" -#include "LaTeXFeatures.h" +#include "InsetLayout.h" #include "Lexer.h" -#include "FuncRequest.h" #include "MetricsInfo.h" -#include "ParagraphParameters.h" +#include "OutputParams.h" +#include "TocBackend.h" #include "frontends/FontMetrics.h" #include "frontends/Painter.h" +#include "support/debug.h" +#include "support/docstream.h" +#include "support/gettext.h" +#include "support/lassert.h" +#include "support/lstrings.h" +#include "support/RefChanger.h" + +using namespace std; + namespace lyx { -using std::endl; -using std::max; -using std::ostream; -using std::string; +InsetCollapsable::InsetCollapsable(Buffer * buf, InsetText::UsePlain ltype) + : InsetText(buf, ltype), status_(Open) +{ + setDrawFrame(true); + setFrameColor(Color_collapsableframe); +} -InsetCollapsable::CollapseStatus InsetCollapsable::status() const +// 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_) +{} + + +InsetCollapsable::~InsetCollapsable() { - return autoOpen_ ? Open : status_; + map::iterator it = view_.begin(); + map::iterator end = view_.end(); + for (; it != end; ++it) + if (it->second.mouse_hover_) + it->first->clearLastInset(this); } -InsetCollapsable::Geometry InsetCollapsable::geometry() const +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(BufferView const & bv) const { switch (decoration()) { - case Classic: - if (status() == Open) { - if (openinlined_) - return LeftButton; - else - return TopButton; - } else - return ButtonOnly; + case InsetLayout::CLASSIC: + if (status(bv) == Open) + return view_[&bv].openinlined_ ? LeftButton : TopButton; + return ButtonOnly; + + case InsetLayout::MINIMALISTIC: + return status(bv) == Open ? NoButton : ButtonOnly ; - case Minimalistic: - return status() == Open ? NoButton : ButtonOnly ; + case InsetLayout::CONGLOMERATE: + return status(bv) == Open ? SubLabel : Corners ; - case Conglomerate: - return status() == Open ? SubLabel : Corners ; + case InsetLayout::DEFAULT: + break; // this shouldn't happen } // dummy return value to shut down a warning, @@ -73,54 +100,19 @@ InsetCollapsable::Geometry InsetCollapsable::geometry() const } -InsetCollapsable::InsetCollapsable - (BufferParams const & bp, CollapseStatus status) - : InsetText(bp), status_(status), - openinlined_(false), autoOpen_(false), mouse_hover_(false) +docstring InsetCollapsable::toolTip(BufferView const & bv, int x, int y) const { - setAutoBreakRows(true); - setDrawFrame(true); - setFrameColor(Color_collapsableframe); - setButtonLabel(); - setLayout(bp); -} - - -InsetCollapsable::InsetCollapsable(InsetCollapsable const & rhs) - : InsetText(rhs), - button_dim(rhs.button_dim), - topx(rhs.topx), - topbaseline(rhs.topbaseline), - layout_(rhs.layout_), - status_(rhs.status_), - openinlined_(rhs.openinlined_), - autoOpen_(rhs.autoOpen_), - // the sole purpose of this copy constructor - mouse_hover_(false) -{ -} - + 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(); -void InsetCollapsable::setLayout(BufferParams const & bp) -{ - // FIXME: put this in the InsetLayout parsing? - // Fallback for lacking inset layout background - layout_.bgcolor = Color_background; - - layout_ = getLayout(bp); - if (layout_.labelfont != inherit_font) - return; - - // FIXME: put this in the InsetLayout parsing? - // Fallback for lacking inset layout labelfont. - layout_.labelfont = sane_font; - layout_.labelfont.decSize(); - layout_.labelfont.decSize(); - layout_.labelfont.setColor(Color_collapsable); + return toolTipText(); } -void InsetCollapsable::write(Buffer const & buf, ostream & os) const +void InsetCollapsable::write(ostream & os) const { os << "status "; switch (status_) { @@ -132,76 +124,46 @@ void InsetCollapsable::write(Buffer const & buf, ostream & os) const break; } os << "\n"; - text_.write(buf, os); + text().write(os); } -void InsetCollapsable::read(Buffer const & buf, Lexer & lex) +void InsetCollapsable::read(Lexer & lex) { - bool token_found = false; - if (lex.isOK()) { - lex.next(); - string const token = lex.getString(); - if (token == "status") { - lex.next(); - string const tmp_token = lex.getString(); - - if (tmp_token == "collapsed") { - status_ = Collapsed; - token_found = true; - } else if (tmp_token == "open") { - status_ = Open; - token_found = true; - } else { - lyxerr << "InsetCollapsable::read: Missing status!" - << endl; - // Take countermeasures - lex.pushToken(token); - } - } else { - lyxerr << "InsetCollapsable::read: Missing 'status'-tag!" - << endl; - // take countermeasures - lex.pushToken(token); - } - } - InsetText::read(buf, lex); - - if (!token_found) - status_ = isOpen() ? Open : Collapsed; + lex.setContext("InsetCollapsable::read"); + string tmp_token; + status_ = Collapsed; + lex >> "status" >> tmp_token; + if (tmp_token == "open") + status_ = Open; + InsetText::read(lex); setButtonLabel(); - setLayout(buf.params()); - - // Force default font, if so requested - // This avoids paragraphs in buffer language that would have a - // foreign language after a document language change, and it ensures - // that all new text in ERT and similar gets the "latex" language, - // since new text inherits the language from the last position of the - // existing text. As a side effect this makes us also robust against - // bugs in LyX that might lead to font changes in ERT in .lyx files. - resetParagraphsFont(); } -Dimension InsetCollapsable::dimensionCollapsed() const +Dimension InsetCollapsable::dimensionCollapsed(BufferView const & bv) const { Dimension dim; - theFontMetrics(layout_.labelfont).buttonText( - layout_.labelstring, dim.wid, dim.asc, dim.des); + FontInfo labelfont(getLabelfont()); + labelfont.realize(sane_font); + theFontMetrics(labelfont).buttonText( + buttonLabel(bv), dim.wid, dim.asc, dim.des); return dim; } void InsetCollapsable::metrics(MetricsInfo & mi, Dimension & dim) const { - autoOpen_ = mi.base.bv->cursor().isInside(this); + view_[mi.base.bv].auto_open_ = mi.base.bv->cursor().isInside(this); FontInfo tmpfont = mi.base.font; - getDrawFont(mi.base.font); + mi.base.font = getFont(); mi.base.font.realize(tmpfont); - switch (geometry()) { + BufferView const & bv = *mi.base.bv; + + switch (geometry(bv)) { case NoButton: InsetText::metrics(mi, dim); break; @@ -213,28 +175,31 @@ void InsetCollapsable::metrics(MetricsInfo & mi, Dimension & dim) const case SubLabel: { InsetText::metrics(mi, dim); // consider width of the inset label - FontInfo font(layout_.labelfont); + FontInfo font(getLabelfont()); font.realize(sane_font); font.decSize(); font.decSize(); int w = 0; int a = 0; int d = 0; - docstring s = layout_.labelstring; - theFontMetrics(font).rectText(s, w, a, d); + theFontMetrics(font).rectText(buttonLabel(bv), w, a, d); dim.des += a + d; break; } case TopButton: case LeftButton: case ButtonOnly: - dim = dimensionCollapsed(); - if (geometry() == TopButton - || geometry() == LeftButton) { + 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) { 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); @@ -251,56 +216,71 @@ 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; } void InsetCollapsable::draw(PainterInfo & pi, int x, int y) const { - autoOpen_ = pi.base.bv->cursor().isInside(this); - ColorCode const old_color = pi.background_color; - pi.background_color = backgroundColor(); + BufferView const & bv = *pi.base.bv; - FontInfo tmpfont = pi.base.font; - getDrawFont(pi.base.font); - pi.base.font.realize(tmpfont); - - // Draw button first -- top, left or only - Dimension dimc = dimensionCollapsed(); + view_[&bv].auto_open_ = bv.cursor().isInside(this); - if (geometry() == TopButton || - geometry() == LeftButton || - geometry() == ButtonOnly) { - button_dim.x1 = x + 0; - button_dim.x2 = x + dimc.width(); - button_dim.y1 = y - dimc.asc; - button_dim.y2 = y + dimc.des; + Changer dummy = pi.base.font.change(getFont(), true); - pi.pain.buttonText(x, y, layout_.labelstring, layout_.labelfont, mouse_hover_); + // Draw button first -- top, left or only + Dimension dimc = dimensionCollapsed(bv); + + 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 = getLabelfont(); + labelfont.setColor(labelColor()); + labelfont.realize(pi.base.font); + pi.pain.buttonText(x, y, buttonLabel(bv), labelfont, + 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(*pi.base.bv); + Dimension const textdim = dimensionHelper(bv); int const baseline = y; int textx, texty; - switch (geometry()) { + 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: @@ -312,88 +292,89 @@ 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() == 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, - layout_.labelfont.color()); - if (internalStatus() == Open) - pi.pain.line(xx1, y + desc, - xx2, y + desc, - layout_.labelfont.color()); + pi.pain.line(xx1, y + desc - 4, + xx1, y + desc, colour); + if (status_ == Open) + 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, - layout_.labelfont.color()); + xx1 + 4, y + desc, colour); pi.pain.line(xx2 - 4, y + desc, - xx2, y + desc, - layout_.labelfont.color()); + xx2, y + desc, colour); } - pi.pain.line(x + textdim.wid - 3, y + desc, x + textdim.wid - 3, y + desc - 4, - layout_.labelfont.color()); + 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() == SubLabel) { - FontInfo font(layout_.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; - docstring s = layout_.labelstring; - theFontMetrics(font).rectText(s, w, a, d); + 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, - s, 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 & cur = pi.base.bv->cursor(); + Cursor const & cur = bv.cursor(); if (cur.isInside(this)) { - y -= textdim.asc; - y += 3; - pi.pain.line(xx1, y + 4, xx1, y, layout_.labelfont.color()); - pi.pain.line(xx1 + 4, y, xx1, y, layout_.labelfont.color()); - pi.pain.line(xx2, y + 4, xx2, y, - layout_.labelfont.color()); - pi.pain.line(xx2 - 4, y, xx2, y, - layout_.labelfont.color()); + 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.background_color = old_color; - - pi.base.font = tmpfont; } void InsetCollapsable::cursorPos(BufferView const & bv, CursorSlice const & sl, bool boundary, int & x, int & y) const { - if (geometry() == ButtonOnly) + if (geometry(bv) == ButtonOnly) status_ = Open; - BOOST_ASSERT(geometry() != ButtonOnly); InsetText::cursorPos(bv, sl, boundary, x, y); - Dimension const textdim = InsetText::dimension(bv); + Dimension const textdim = dimensionHelper(bv); - switch (geometry()) { + switch (geometry(bv)) { case LeftButton: - x += dimensionCollapsed().wid; + x += dimensionCollapsed(bv).wid; break; case TopButton: { - y += dimensionCollapsed().des + textdim.asc; + y += dimensionCollapsed(bv).des + textdim.asc; break; } case NoButton: @@ -408,21 +389,27 @@ void InsetCollapsable::cursorPos(BufferView const & bv, } -Inset::EDITABLE InsetCollapsable::editable() const +bool InsetCollapsable::editable() const { - return geometry() != ButtonOnly? HIGHLY_EDITABLE : IS_EDITABLE; + 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); } @@ -431,7 +418,7 @@ docstring const InsetCollapsable::getNewLabel(docstring const & l) const docstring label; pos_type const max_length = 15; pos_type const p_siz = paragraphs().begin()->size(); - pos_type const n = std::min(max_length, p_siz); + pos_type const n = min(max_length, p_siz); pos_type i = 0; pos_type j = 0; for (; i < n && j < p_siz; ++j) { @@ -447,20 +434,20 @@ docstring const InsetCollapsable::getNewLabel(docstring const & l) const } -void InsetCollapsable::edit(Cursor & cur, bool left) +void InsetCollapsable::edit(Cursor & cur, bool front, EntryDirection entry_from) { //lyxerr << "InsetCollapsable: edit left/right" << endl; cur.push(*this); - InsetText::edit(cur, left); + InsetText::edit(cur, front, entry_from); } Inset * InsetCollapsable::editXY(Cursor & cur, int x, int y) { //lyxerr << "InsetCollapsable: edit xy" << endl; - if (geometry() == ButtonOnly - || (button_dim.contains(x, y) - && geometry() != NoButton)) + if (geometry(cur.bv()) == ButtonOnly + || (view_[&cur.bv()].button_dim_.contains(x, y) + && geometry(cur.bv()) != NoButton)) return this; cur.push(*this); return InsetText::editXY(cur, x, y); @@ -472,23 +459,27 @@ 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 (cmd.button() == mouse_button::button1 - && hitButton(cmd) - && geometry() != NoButton) { - // reset selection if necessary (see bug 3060) - if (cur.selection()) - cur.bv().cursor().clearSelection(); - else - cur.noUpdate(); - cur.dispatched(); - break; - } - if (geometry() == NoButton) - InsetText::doDispatch(cur, cmd); - else if (geometry() != ButtonOnly - && !hitButton(cmd)) + if (hitButton) { + switch (cmd.button()) { + case mouse_button::button1: + case mouse_button::button3: + // Pass the command to the enclosing InsetText, + // so that the cursor gets set. + cur.undispatched(); + break; + case mouse_button::none: + case mouse_button::button2: + case mouse_button::button4: + case mouse_button::button5: + // Nothing to do. + cur.noScreenUpdate(); + break; + } + } else if (geometry(cur.bv()) != ButtonOnly) InsetText::doDispatch(cur, cmd); else cur.undispatched(); @@ -497,64 +488,43 @@ void InsetCollapsable::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_MOUSE_MOTION: case LFUN_MOUSE_DOUBLE: case LFUN_MOUSE_TRIPLE: - if (geometry() == NoButton) - InsetText::doDispatch(cur, cmd); - else if (geometry() != ButtonOnly - && !hitButton(cmd)) + if (hitButton) + cur.noScreenUpdate(); + else if (geometry(cur.bv()) != ButtonOnly) InsetText::doDispatch(cur, cmd); else cur.undispatched(); break; case LFUN_MOUSE_RELEASE: - if (cmd.button() == mouse_button::button3) { - // There is no button to right click: - if (geometry() == Corners || - geometry() == SubLabel || - geometry() == NoButton) { - if (internalStatus() == Open) - setStatus(cur, Collapsed); - else - setStatus(cur, Open); - break; - } else { - // Open the Inset - // configuration dialog - showInsetDialog(&cur.bv()); - break; - } - } - - if (geometry() == NoButton) { + if (!hitButton) { // The mouse click has to be within the inset! - InsetText::doDispatch(cur, cmd); + if (geometry(cur.bv()) != ButtonOnly) + InsetText::doDispatch(cur, cmd); + else + cur.undispatched(); break; } - - if (cmd.button() == mouse_button::button1 && hitButton(cmd)) { - // if we are selecting, we do not want to - // toggle the inset. - if (cur.selection()) - break; - // Left button is clicked, the user asks to - // toggle the inset visual state. - cur.dispatched(); - cur.updateFlags(Update::Force | Update::FitCursor); - if (geometry() == ButtonOnly) { - setStatus(cur, Open); - edit(cur, true); - } - else { - setStatus(cur, Collapsed); - } - cur.bv().cursor() = cur; + if (cmd.button() != mouse_button::button1) { + // Nothing to do. + cur.noScreenUpdate(); break; } - - // The mouse click is within the opened inset. - if (geometry() == TopButton - || geometry() == LeftButton) - InsetText::doDispatch(cur, cmd); + // if we are selecting, we do not want to + // toggle the inset. + if (cur.selection()) + break; + // Left button is clicked, the user asks to + // toggle the inset visual state. + cur.dispatched(); + cur.screenUpdateFlags(Update::Force | Update::FitCursor); + if (geometry(cur.bv()) == ButtonOnly) { + setStatus(cur, Open); + edit(cur, true); + } + else + setStatus(cur, Collapsed); + cur.bv().cursor() = cur; break; case LFUN_INSET_TOGGLE: @@ -563,203 +533,65 @@ void InsetCollapsable::doDispatch(Cursor & cur, FuncRequest & cmd) else if (cmd.argument() == "close") setStatus(cur, Collapsed); else if (cmd.argument() == "toggle" || cmd.argument().empty()) - if (internalStatus() == Open) { + if (status_ == Open) setStatus(cur, Collapsed); - if (geometry() == ButtonOnly) - cur.top().forwardPos(); - } else + else setStatus(cur, Open); else // if assign or anything else cur.undispatched(); cur.dispatched(); break; - case LFUN_PASTE: - case LFUN_CLIPBOARD_PASTE: - case LFUN_PRIMARY_SELECTION_PASTE: { - InsetText::doDispatch(cur, cmd); - // Since we can only store plain text, we must reset all - // attributes. - // FIXME: Change only the pasted paragraphs - - resetParagraphsFont(); - break; - } - default: - if (layout_.forceltr) { - // Force any new text to latex_language - // FIXME: This should only be necessary in constructor, but - // new paragraphs that are created by pressing enter at the - // start of an existing paragraph get the buffer language - // and not latex_language, so we take this brute force - // approach. - cur.current_font.setLanguage(latex_language); - cur.real_current_font.setLanguage(latex_language); - } InsetText::doDispatch(cur, cmd); break; } } -bool InsetCollapsable::allowMultiPar() const +bool InsetCollapsable::getStatus(Cursor & cur, FuncRequest const & cmd, + FuncStatus & flag) const { - return layout_.multipar; -} - + switch (cmd.action()) { + case LFUN_INSET_TOGGLE: + if (cmd.argument() == "open") + flag.setEnabled(status_ != Open); + else if (cmd.argument() == "close") + flag.setEnabled(status_ == Open); + else if (cmd.argument() == "toggle" || cmd.argument().empty()) { + flag.setEnabled(true); + flag.setOnOff(status_ == Open); + } else + flag.setEnabled(false); + return true; -void InsetCollapsable::resetParagraphsFont() -{ - Font font; - font.fontInfo() = sane_font; - if (layout_.forceltr) - font.setLanguage(latex_language); - if (layout_.passthru) { - ParagraphList::iterator par = paragraphs().begin(); - ParagraphList::iterator const end = paragraphs().end(); - while (par != end) { - par->resetFonts(font); - par->params().clear(); - ++par; - } + default: + return InsetText::getStatus(cur, cmd, flag); } } -void InsetCollapsable::getDrawFont(FontInfo & font) const +void InsetCollapsable::setLabel(docstring const & l) { - font = layout_.font; + labelstring_ = l; } -bool InsetCollapsable::getStatus(Cursor & cur, FuncRequest const & cmd, - FuncStatus & flag) const +docstring InsetCollapsable::getLabel() const { - switch (cmd.action) { - // suppress these - 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_SPECIAL_CARON: - 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_BIBITEM_INSERT: - case LFUN_BOX_INSERT: - case LFUN_BRANCH_INSERT: - case LFUN_BREAK_LINE: - case LFUN_CAPTION_INSERT: - case LFUN_CLEARPAGE_INSERT: - case LFUN_CLEARDOUBLEPAGE_INSERT: - case LFUN_DEPTH_DECREMENT: - case LFUN_DEPTH_INCREMENT: - case LFUN_DOTS_INSERT: - case LFUN_END_OF_SENTENCE_PERIOD_INSERT: - case LFUN_ENVIRONMENT_INSERT: - case LFUN_ERT_INSERT: - case LFUN_FILE_INSERT: - case LFUN_FLEX_INSERT: - case LFUN_FLOAT_INSERT: - case LFUN_FLOAT_LIST: - case LFUN_FLOAT_WIDE_INSERT: - case LFUN_FONT_BOLD: - case LFUN_FONT_TYPEWRITER: - case LFUN_FONT_DEFAULT: - case LFUN_FONT_EMPH: - case LFUN_FONT_FREE_APPLY: - case LFUN_FONT_FREE_UPDATE: - 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_FOOTNOTE_INSERT: - case LFUN_HFILL_INSERT: - case LFUN_HYPERLINK_INSERT: - case LFUN_HYPHENATION_POINT_INSERT: - case LFUN_INDEX_INSERT: - case LFUN_INDEX_PRINT: - case LFUN_INSET_INSERT: - case LFUN_LABEL_GOTO: - case LFUN_LABEL_INSERT: - case LFUN_LIGATURE_BREAK_INSERT: - case LFUN_LINE_INSERT: - case LFUN_PAGEBREAK_INSERT: - case LFUN_LAYOUT: - case LFUN_LAYOUT_PARAGRAPH: - case LFUN_LAYOUT_TABULAR: - case LFUN_MARGINALNOTE_INSERT: - case LFUN_MATH_DISPLAY: - case LFUN_MATH_INSERT: - case LFUN_MATH_MATRIX: - case LFUN_MATH_MODE: - case LFUN_MENU_OPEN: - case LFUN_MENU_SEPARATOR_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_PARAGRAPH_PARAMS: - case LFUN_PARAGRAPH_PARAMS_APPLY: - case LFUN_PARAGRAPH_SPACING: - case LFUN_PARAGRAPH_UPDATE: - 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_TABULAR_INSERT: - case LFUN_TOC_INSERT: - case LFUN_WRAP_INSERT: - if (layout_.passthru) { - flag.enabled(false); - return true; - } else - return InsetText::getStatus(cur, cmd, flag); - - case LFUN_INSET_TOGGLE: - if (cmd.argument() == "open" || cmd.argument() == "close" || - cmd.argument() == "toggle") - flag.enabled(true); - else - flag.enabled(false); - return true; - - case LFUN_LANGUAGE: - flag.enabled(!layout_.forceltr); - return InsetText::getStatus(cur, cmd, flag); - - case LFUN_BREAK_PARAGRAPH: - case LFUN_BREAK_PARAGRAPH_SKIP: - flag.enabled(layout_.multipar); - return true; - - default: - return InsetText::getStatus(cur, cmd, flag); - } + InsetLayout const & il = getLayout(); + return labelstring_.empty() ? + translateIfPossible(il.labelstring()) : labelstring_; } -void InsetCollapsable::setLabel(docstring const & l) +docstring const InsetCollapsable::buttonLabel(BufferView const & bv) const { - layout_.labelstring = l; + InsetLayout const & il = getLayout(); + docstring const label = getLabel(); + if (!il.contentaslabel() || geometry(bv) != ButtonOnly) + return label; + return getNewLabel(label); } @@ -772,87 +604,87 @@ void InsetCollapsable::setStatus(Cursor & cur, CollapseStatus status) } -void InsetCollapsable::setLabelFont(FontInfo const & font) +InsetLayout::InsetDecoration InsetCollapsable::decoration() const { - layout_.labelfont = font; + InsetLayout::InsetDecoration const dec = getLayout().decoration(); + return dec == InsetLayout::DEFAULT ? InsetLayout::CLASSIC : dec; } -void InsetCollapsable::setLabelColor(ColorCode code) +string InsetCollapsable::contextMenu(BufferView const & bv, int x, + int y) const { - layout_.labelfont.setColor(code); -} + 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; -docstring InsetCollapsable::floatName(string const & type, BufferParams const & bp) const -{ - FloatList const & floats = bp.getTextClass().floats(); - FloatList::const_iterator it = floats[type]; - // FIXME UNICODE - return (it == floats.end()) ? from_ascii(type) : bp.B_(it->second.name()); + 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; + + return it_context_menu; } -InsetCollapsable::Decoration InsetCollapsable::decoration() const +string InsetCollapsable::contextMenuName() const { - if (layout_.decoration == "classic") - return Classic; - if (layout_.decoration == "minimalistic") - return Minimalistic; - if (layout_.decoration == "conglomerate") - return Conglomerate; - if (name() == from_ascii("Flex")) - return Conglomerate; - return Classic; + if (decoration() == InsetLayout::CONGLOMERATE) + return "context-conglomerate"; + else + return "context-collapsable"; } -int InsetCollapsable::latex(Buffer const & buf, odocstream & os, - OutputParams const & runparams) const +bool InsetCollapsable::canPaintChange(BufferView const & bv) 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 (!layout_.latexname.empty()) { - if (layout_.latextype == "command") { - // FIXME UNICODE - if (runparams.moving_arg) - os << "\\protect"; - os << '\\' << from_utf8(layout_.latexname); - if (!layout_.latexparam.empty()) - os << from_utf8(layout_.latexparam); - os << '{'; - } else if (layout_.latextype == "environment") { - os << "%\n\\begin{" << from_utf8(layout_.latexname) << "}\n"; - if (!layout_.latexparam.empty()) - os << from_utf8(layout_.latexparam); - } - } - OutputParams rp = runparams; - if (layout_.passthru) - rp.verbatim = true; - if (layout_.needprotect) - rp.moving_arg = true; - int i = InsetText::latex(buf, os, rp); - if (!layout_.latexname.empty()) { - if (layout_.latextype == "command") { - os << "}"; - } else if (layout_.latextype == "environment") { - os << "\n\\end{" << from_utf8(layout_.latexname) << "}\n"; - i += 4; - } + // 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 i; + return true; } -void InsetCollapsable::validate(LaTeXFeatures & features) const +void InsetCollapsable::addToToc(DocIterator const & cpit, bool output_active, + UpdateType utype) const { - // Force inclusion of preamble snippet in layout file - features.require(layout_.name); - InsetText::validate(features); + bool doing_output = output_active && producesOutput(); + InsetLayout const & layout = getLayout(); + if (layout.addToToc()) { + TocBuilder & b = buffer().tocBackend().builder(layout.tocType()); + // Cursor inside the inset + DocIterator pit = cpit; + pit.push_back(CursorSlice(const_cast(*this))); + docstring const label = getLabel(); + b.pushItem(pit, label + (label.empty() ? "" : ": "), output_active); + // Proceed with the rest of the inset. + InsetText::addToToc(cpit, doing_output, utype); + if (layout.isTocCaption()) { + docstring str; + text().forOutliner(str, TOC_ENTRY_LENGTH); + b.argumentItem(str); + } + b.pop(); + } else + InsetText::addToToc(cpit, doing_output, utype); } + } // namespace lyx