X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetCollapsable.cpp;h=4108be23937c5ed427f89c46567370bda6a4666c;hb=0fcae6cc10640f2d5a591152d59d252bb6dc0757;hp=1c7ec55961c0103f498b8f8fdde3c74f3527aaa3;hpb=a746aa52146257c0e7a2d60123f63dccad5b2751;p=lyx.git diff --git a/src/insets/InsetCollapsable.cpp b/src/insets/InsetCollapsable.cpp index 1c7ec55961..4108be2393 100644 --- a/src/insets/InsetCollapsable.cpp +++ b/src/insets/InsetCollapsable.cpp @@ -27,7 +27,6 @@ #include "Lexer.h" #include "FuncRequest.h" #include "MetricsInfo.h" -#include "Paragraph.h" #include "frontends/FontMetrics.h" #include "frontends/Painter.h" @@ -46,13 +45,38 @@ using std::ostream; InsetCollapsable::CollapseStatus InsetCollapsable::status() const { - return (autoOpen_ && status_ != Inlined) ? Open : status_; + return autoOpen_ ? Open : status_; +} + + +InsetCollapsable::Geometry InsetCollapsable::geometry() const +{ + switch (decoration()) { + case Classic: + if (status_ == Open || autoOpen_) { + if (openinlined_) + return LeftButton; + else + return TopButton; + } else + return ButtonOnly; + + case Minimalistic: + return NoButton; + + case Conglomerate: + return status_ == Open ? SubLabel : Corners; + } + + // dummy return value to shut down a warning, + // this is dead code. + return NoButton; } InsetCollapsable::InsetCollapsable (BufferParams const & bp, CollapseStatus status) - : InsetText(bp), label(from_ascii("Label")), status_(status), + : InsetText(bp), status_(status), openinlined_(false), autoOpen_(false), mouse_hover_(false) { setAutoBreakRows(true); @@ -63,12 +87,11 @@ InsetCollapsable::InsetCollapsable InsetCollapsable::InsetCollapsable(InsetCollapsable const & rhs) - : InsetText(rhs), - labelfont_(rhs.labelfont_), + : InsetText(rhs), button_dim(rhs.button_dim), topx(rhs.topx), topbaseline(rhs.topbaseline), - label(rhs.label), + layout_(rhs.layout_), status_(rhs.status_), openinlined_(rhs.openinlined_), autoOpen_(rhs.autoOpen_), @@ -79,6 +102,12 @@ InsetCollapsable::InsetCollapsable(InsetCollapsable const & rhs) } +void InsetCollapsable::setLayout(BufferParams const & bp) +{ + layout_ = getLayout(bp); +} + + void InsetCollapsable::write(Buffer const & buf, ostream & os) const { os << "status "; @@ -89,9 +118,6 @@ void InsetCollapsable::write(Buffer const & buf, ostream & os) const case Collapsed: os << "collapsed"; break; - case Inlined: - os << "inlined"; - break; } os << "\n"; text_.write(buf, os); @@ -108,10 +134,7 @@ void InsetCollapsable::read(Buffer const & buf, Lexer & lex) lex.next(); string const tmp_token = lex.getString(); - if (tmp_token == "inlined") { - status_ = Inlined; - token_found = true; - } else if (tmp_token == "collapsed") { + if (tmp_token == "collapsed") { status_ = Collapsed; token_found = true; } else if (tmp_token == "open") { @@ -142,8 +165,8 @@ void InsetCollapsable::read(Buffer const & buf, Lexer & lex) Dimension InsetCollapsable::dimensionCollapsed() const { Dimension dim; - theFontMetrics(labelfont_).buttonText( - label, dim.wid, dim.asc, dim.des); + theFontMetrics(layout_.labelfont).buttonText( + layout_.labelstring, dim.wid, dim.asc, dim.des); return dim; } @@ -153,14 +176,39 @@ bool InsetCollapsable::metrics(MetricsInfo & mi, Dimension & dim) const autoOpen_ = mi.base.bv->cursor().isInside(this); mi.base.textwidth -= (int) (1.5 * TEXT_TO_INSET_OFFSET); - if (status() == Inlined) { + switch (decoration()) { + case Minimalistic: + InsetText::metrics(mi, dim); + break; + case Conglomerate: InsetText::metrics(mi, dim); - } else { - dim = dimensionCollapsed(); if (status() == Open) { + // consider width of the inset label + Font font(layout_.labelfont); + font.realize(Font(Font::ALL_SANE)); + font.decSize(); + font.decSize(); + int w = 0; + int a = 0; + int d = 0; + docstring s = layout_.labelstring; + theFontMetrics(font).rectText(s, w, a, d); + dim.wid = max(dim.wid, w); + } + if (status() == Open) + dim.des += ascent(); + else { + dim.des -= 3; + dim.asc -= 3; + } + break; + case Classic: + dim = dimensionCollapsed(); + if (geometry() == TopButton + || geometry() == LeftButton) { InsetText::metrics(mi, textdim_); // This expression should not contain mi.base.texwidth - openinlined_ = !hasFixedWidth() + openinlined_ = !hasFixedWidth() && textdim_.wid < 0.5 * mi.base.bv->workWidth(); if (openinlined_) { // Correct for button width, and re-fit @@ -176,6 +224,7 @@ bool InsetCollapsable::metrics(MetricsInfo & mi, Dimension & dim) const dim.wid = max(dim.wid, mi.base.textwidth); } } + break; } dim.asc += TEXT_TO_INSET_OFFSET; dim.des += TEXT_TO_INSET_OFFSET; @@ -197,29 +246,99 @@ bool InsetCollapsable::setMouseHover(bool mouse_hover) void InsetCollapsable::draw(PainterInfo & pi, int x, int y) const { const int xx = x + TEXT_TO_INSET_OFFSET; - if (status() == Inlined) { - InsetText::draw(pi, xx, y); - } else { - Dimension dimc = dimensionCollapsed(); - int const top = y - ascent() + TEXT_TO_INSET_OFFSET; + + // Draw button first -- top, left or only + Dimension dimc = dimensionCollapsed(); + int const top = y - ascent() + TEXT_TO_INSET_OFFSET; + if (decoration() == Classic) { button_dim.x1 = xx + 0; button_dim.x2 = xx + dimc.width(); button_dim.y1 = top; button_dim.y2 = top + dimc.height(); - pi.pain.buttonText(xx, top + dimc.asc, label, labelfont_, mouse_hover_); + pi.pain.buttonText(xx, top + dimc.asc, layout_.labelstring, layout_.labelfont, mouse_hover_); + } + + int textx, texty; + switch (geometry()) { + case LeftButton: + textx = xx + dimc.width(); + texty = top + textdim_.asc; + InsetText::draw(pi, textx, texty); + break; + case TopButton: + textx = xx; + texty = top + dimc.height() + textdim_.asc; + InsetText::draw(pi, textx, texty); + break; + case ButtonOnly: + break; + case NoButton: + textx = xx; + texty = y + textdim_.asc; + InsetText::draw(pi, textx, texty); + break; + case SubLabel: + case Corners: + textx = xx; + texty = y + textdim_.asc; + const_cast(this)->setDrawFrame(false); + InsetText::draw(pi, textx, texty); + const_cast(this)->setDrawFrame(true); + + int desc = InsetText::descent(); + if (status() == Open) + desc -= ascent(); + else + desc -= 3; + + pi.pain.line(x, y + desc - 4, x, y + desc, + layout_.labelfont.color()); + if (internalStatus() == Open) + pi.pain.line(x, y + desc, + x + dim_.wid - 3, y + desc, + layout_.labelfont.color()); + else { + // Make status_ value visible: + pi.pain.line(x, y + desc, + x + 4, y + desc, + layout_.labelfont.color()); + pi.pain.line(x + dim_.wid - 7, y + desc, + x + dim_.wid -3, y + desc, + layout_.labelfont.color()); + } + pi.pain.line(x + dim_.wid - 3, y + desc, x + dim_.wid - 3, y + desc - 4, + layout_.labelfont.color()); + // the label of the charstyle. Can be toggled. if (status() == Open) { - int textx, texty; - if (openinlined_) { - textx = xx + dimc.width(); - texty = top + textdim_.asc; - } else { - textx = xx; - texty = top + dimc.height() + textdim_.asc; - } - InsetText::draw(pi, textx, texty); + Font font(layout_.labelfont); + font.realize(Font(Font::ALL_SANE)); + font.decSize(); + font.decSize(); + int w = 0; + int a = 0; + int d = 0; + // FIXME UNICODE + docstring s = layout_.labelstring; + theFontMetrics(font).rectText(s, w, a, d); + pi.pain.rectText(x + (dim_.wid - w) / 2, y + desc + a, + s, font, Color::none, Color::none); + } + + // a visual cue when the cursor is inside the inset + Cursor & cur = pi.base.bv->cursor(); + if (cur.isInside(this)) { + y -= ascent(); + y += 3; + pi.pain.line(x, y + 4, x, y, layout_.labelfont.color()); + pi.pain.line(x + 4, y, x, y, layout_.labelfont.color()); + pi.pain.line(x + dim_.wid - 3, y + 4, x + dim_.wid - 3, y, + layout_.labelfont.color()); + pi.pain.line(x + dim_.wid - 7, y, x + dim_.wid - 3, y, + layout_.labelfont.color()); } + break; } setPosCache(pi, x, y); } @@ -228,30 +347,49 @@ void InsetCollapsable::draw(PainterInfo & pi, int x, int y) const void InsetCollapsable::drawSelection(PainterInfo & pi, int x, int y) const { x += TEXT_TO_INSET_OFFSET; - if (status() == Open) { - if (openinlined_) - x += dimensionCollapsed().wid; - else - y += dimensionCollapsed().des + textdim_.asc; - } - if (status() != Collapsed) + switch (geometry()) { + case LeftButton: + x += dimensionCollapsed().wid; + InsetText::drawSelection(pi, x, y); + break; + case TopButton: + y += dimensionCollapsed().des + textdim_.asc; + InsetText::drawSelection(pi, x, y); + break; + case ButtonOnly: + break; + case NoButton: + case SubLabel: + case Corners: InsetText::drawSelection(pi, x, y); + break; + } } -void InsetCollapsable::cursorPos(BufferView const & bv, +void InsetCollapsable::cursorPos(BufferView const & bv, CursorSlice const & sl, bool boundary, int & x, int & y) const { - BOOST_ASSERT(status() != Collapsed); + BOOST_ASSERT(geometry() != ButtonOnly); InsetText::cursorPos(bv, sl, boundary, x, y); - if (status() == Open) { - if (openinlined_) - x += dimensionCollapsed().wid; - else - y += dimensionCollapsed().height() - ascent() - + TEXT_TO_INSET_OFFSET + textdim_.asc; + switch (geometry()) { + case LeftButton: + x += dimensionCollapsed().wid; + break; + case TopButton: + y += dimensionCollapsed().height() - ascent() + + TEXT_TO_INSET_OFFSET + textdim_.asc; + break; + case NoButton: + case SubLabel: + case Corners: + // Do nothing + break; + case ButtonOnly: + // Cannot get here + break; } x += TEXT_TO_INSET_OFFSET; } @@ -259,13 +397,13 @@ void InsetCollapsable::cursorPos(BufferView const & bv, Inset::EDITABLE InsetCollapsable::editable() const { - return status() != Collapsed ? HIGHLY_EDITABLE : IS_EDITABLE; + return geometry() != ButtonOnly? HIGHLY_EDITABLE : IS_EDITABLE; } bool InsetCollapsable::descendable() const { - return status() != Collapsed; + return geometry() != ButtonOnly; } @@ -307,7 +445,9 @@ void InsetCollapsable::edit(Cursor & cur, bool left) Inset * InsetCollapsable::editXY(Cursor & cur, int x, int y) { //lyxerr << "InsetCollapsable: edit xy" << endl; - if (status() == Collapsed || (button_dim.contains(x, y) && status() != Inlined)) + if (geometry() == ButtonOnly + || (button_dim.contains(x, y) + && decoration() != Minimalistic)) return this; cur.push(*this); return InsetText::editXY(cur, x, y); @@ -321,7 +461,9 @@ void InsetCollapsable::doDispatch(Cursor & cur, FuncRequest & cmd) switch (cmd.action) { case LFUN_MOUSE_PRESS: - if (cmd.button() == mouse_button::button1 && hitButton(cmd) && status() != Inlined) { + if (cmd.button() == mouse_button::button1 + && hitButton(cmd) + && decoration() != Minimalistic) { // reset selection if necessary (see bug 3060) if (cur.selection()) cur.bv().cursor().clearSelection(); @@ -330,9 +472,10 @@ void InsetCollapsable::doDispatch(Cursor & cur, FuncRequest & cmd) cur.dispatched(); break; } - if (status() == Inlined) + if (decoration() == Minimalistic) InsetText::doDispatch(cur, cmd); - else if (status() == Open && !hitButton(cmd)) + else if (geometry() != ButtonOnly + && !hitButton(cmd)) InsetText::doDispatch(cur, cmd); else cur.undispatched(); @@ -341,9 +484,10 @@ void InsetCollapsable::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_MOUSE_MOTION: case LFUN_MOUSE_DOUBLE: case LFUN_MOUSE_TRIPLE: - if (status_ == Inlined) + if (decoration() == Minimalistic) InsetText::doDispatch(cur, cmd); - else if (status() && !hitButton(cmd)) + else if (geometry() != ButtonOnly + && !hitButton(cmd)) InsetText::doDispatch(cur, cmd); else cur.undispatched(); @@ -351,12 +495,22 @@ void InsetCollapsable::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_MOUSE_RELEASE: if (cmd.button() == mouse_button::button3) { - // Open the Inset configuration dialog - showInsetDialog(&cur.bv()); - break; + if (decoration() == Conglomerate) { + + if (internalStatus() == Open) + setStatus(cur, Collapsed); + else + setStatus(cur, Open); + break; + } else { + // Open the Inset + // configuration dialog + showInsetDialog(&cur.bv()); + break; + } } - if (status() == Inlined) { + if (decoration() == Minimalistic) { // The mouse click has to be within the inset! InsetText::doDispatch(cur, cmd); break; @@ -371,7 +525,7 @@ void InsetCollapsable::doDispatch(Cursor & cur, FuncRequest & cmd) // toggle the inset visual state. cur.dispatched(); cur.updateFlags(Update::Force | Update::FitCursor); - if (status() == Collapsed) { + if (geometry() == ButtonOnly) { setStatus(cur, Open); edit(cur, true); } @@ -383,7 +537,8 @@ void InsetCollapsable::doDispatch(Cursor & cur, FuncRequest & cmd) } // The mouse click is within the opened inset. - if (status() == Open) + if (geometry() == TopButton + || geometry() == LeftButton) InsetText::doDispatch(cur, cmd); break; @@ -393,11 +548,11 @@ void InsetCollapsable::doDispatch(Cursor & cur, FuncRequest & cmd) else if (cmd.argument() == "close") setStatus(cur, Collapsed); else if (cmd.argument() == "toggle" || cmd.argument().empty()) - if (isOpen()) { + if (internalStatus() == Open) { setStatus(cur, Collapsed); - cur.forwardPosNoDescend(); - } - else + if (geometry() == ButtonOnly) + cur.top().forwardPos(); + } else setStatus(cur, Open); else // if assign or anything else cur.undispatched(); @@ -432,7 +587,7 @@ bool InsetCollapsable::getStatus(Cursor & cur, FuncRequest const & cmd, void InsetCollapsable::setLabel(docstring const & l) { - label = l; + layout_.labelstring = l; } @@ -442,15 +597,16 @@ void InsetCollapsable::setStatus(Cursor & cur, CollapseStatus status) setButtonLabel(); if (status_ == Collapsed) cur.leaveInset(*this); - // Because we save CollapseStatus in lyx file, change of status - // should lead to a dirty buffer. (This fixes bug 2993). - cur.bv().buffer()->markDirty(); + // Because the collapse status is part of the inset and thus an + // integral part of the Buffer contents a changed status must be + // signaled to all views of current buffer. + cur.bv().buffer().changed(); } -void InsetCollapsable::setLabelFont(Font & font) +void InsetCollapsable::setLabelFont(Font const & font) { - labelfont_ = font; + layout_.labelfont = font; } docstring InsetCollapsable::floatName(string const & type, BufferParams const & bp) const @@ -462,4 +618,37 @@ docstring InsetCollapsable::floatName(string const & type, BufferParams const & } + +int InsetCollapsable::latex(Buffer const & buf, 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 (!layout_.latexname.empty()) { + if (layout_.latextype == "command") { + // FIXME UNICODE + 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); + } + } + int i = InsetText::latex(buf, os, runparams); + 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 i; +} + + } // namespace lyx