#include "MathMacroArgument.h"
#include "Buffer.h"
+#include "BufferView.h"
#include "Color.h"
#include "Cursor.h"
#include "support/debug.h"
using support::bformat;
+//////////////////////////////////////////////////////////////////////
+
+class InsetLabelBox : public InsetMathNest {
+public:
+ ///
+ InsetLabelBox(MathAtom const & atom, docstring label,
+ MathMacroTemplate const & parent, bool frame = false);
+ InsetLabelBox(docstring label, MathMacroTemplate const & parent,
+ bool frame = false);
+ ///
+ void metrics(MetricsInfo & mi, Dimension & dim) const;
+ ///
+ void draw(PainterInfo &, int x, int y) const;
+
+private:
+ ///
+ MathMacroTemplate const & parent_;
+ ///
+ Inset * clone() const;
+ ///
+ docstring const label_;
+ ///
+ bool frame_;
+ ///
+ mutable Dimension cellDim_;
+};
+
+
+InsetLabelBox::InsetLabelBox(MathAtom const & atom, docstring label,
+ MathMacroTemplate const & parent, bool frame)
+: InsetMathNest(1), parent_(parent), label_(label), frame_(frame)
+{
+ cell(0).insert(0, atom);
+}
+
+InsetLabelBox::InsetLabelBox(docstring label,
+ MathMacroTemplate const & parent, bool frame)
+: InsetMathNest(1), parent_(parent), label_(label), frame_(frame)
+{
+}
+
+
+Inset * InsetLabelBox::clone() const
+{
+ return new InsetLabelBox(*this);
+}
+
+
+void InsetLabelBox::metrics(MetricsInfo & mi, Dimension & dim) const
+{
+ // kernel
+ cell(0).metrics(mi, dim);
+ cellDim_ = dim;
+
+ // frame
+ if (frame_) {
+ dim.wid += 6;
+ dim.asc += 5;
+ dim.des += 5;
+ }
+
+ // adjust to common height in main metrics phase
+ if (!parent_.premetrics()) {
+ dim.asc = max(dim.asc, parent_.commonLabelBoxAscent());
+ dim.des = max(dim.des, parent_.commonLabelBoxDescent());
+ }
+
+ // label
+ if (label_.length() > 0) {
+ // grey
+ FontInfo font = sane_font;
+ font.setSize(FONT_SIZE_TINY);
+ font.setColor(Color_mathmacrolabel);
+
+ // make space for label and box
+ int lwid = mathed_string_width(font, label_);
+ int maxasc;
+ int maxdes;
+ math_font_max_dim(font, maxasc, maxdes);
+
+ dim.wid = max(dim.wid, lwid + 2);
+
+ // space for the label
+ if (!parent_.premetrics())
+ dim.des += maxasc + maxdes + 1;
+ }
+
+ setDimCache(mi, dim);
+}
+
+
+void InsetLabelBox::draw(PainterInfo & pi, int x, int y) const
+{
+ Dimension const dim = dimension(*pi.base.bv);
+
+ // kernel
+ cell(0).draw(pi, x + (dim.wid - cellDim_.wid) / 2, y);
+
+ // label
+ if (label_.length() > 0) {
+ // grey
+ FontInfo font = sane_font;
+ font.setSize(FONT_SIZE_TINY);
+ font.setColor(Color_mathmacrolabel);
+
+ // make space for label and box
+ int lwid = mathed_string_width(font, label_);
+ int maxasc;
+ int maxdes;
+ math_font_max_dim(font, maxasc, maxdes);
+
+ if (lwid < dim.wid)
+ pi.pain.text(x + (dim.wid - lwid) / 2, y + dim.des - maxdes, label_, font);
+ else
+ pi.pain.text(x, y + dim.des - maxdes, label_, font);
+ }
+
+ // draw frame
+ int boxHeight = parent_.commonLabelBoxAscent() + parent_.commonLabelBoxDescent();
+ if (frame_) {
+ pi.pain.rectangle(x + 1, y - dim.ascent() + 1,
+ dim.wid - 2, boxHeight - 2,
+ Color_mathline);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////
class InsetMathWrapper : public InsetMath {
public:
}
+///////////////////////////////////////////////////////////////////////
+
+class InsetNameWrapper : public InsetMathWrapper {
+public:
+ ///
+ InsetNameWrapper(MathData const * value, MathMacroTemplate const & parent);
+ ///
+ void metrics(MetricsInfo & mi, Dimension & dim) const;
+ ///
+ void draw(PainterInfo &, int x, int y) const;
+
+private:
+ ///
+ MathMacroTemplate const & parent_;
+ ///
+ Inset * clone() const;
+};
+
+
+InsetNameWrapper::InsetNameWrapper(MathData const * value,
+ MathMacroTemplate const & parent)
+ : InsetMathWrapper(value), parent_(parent)
+{
+}
+
+
+Inset * InsetNameWrapper::clone() const
+{
+ return new InsetNameWrapper(*this);
+}
+
+
+void InsetNameWrapper::metrics(MetricsInfo & mi, Dimension & dim) const
+{
+ InsetMathWrapper::metrics(mi, dim);
+ dim.wid += mathed_string_width(mi.base.font, from_ascii("\\"));
+}
+
+
+void InsetNameWrapper::draw(PainterInfo & pi, int x, int y) const
+{
+ // create fonts
+ PainterInfo namepi = pi;
+ if (parent_.validMacro())
+ namepi.base.font.setColor(Color_latex);
+ else
+ namepi.base.font.setColor(Color_error);
+
+ // draw backslash
+ pi.pain.text(x, y, from_ascii("\\"), namepi.base.font);
+ x += mathed_string_width(namepi.base.font, from_ascii("\\"));
+
+ // draw name
+ InsetMathWrapper::draw(namepi, x, y);
+}
+
+
+///////////////////////////////////////////////////////////////////////
+
+
MathMacroTemplate::MathMacroTemplate()
: InsetMathNest(3), numargs_(0), optionals_(0),
- type_(MacroTypeNewcommand)
+ type_(MacroTypeNewcommand), editing_(false), lookOutdated_(true)
{
initMath();
}
MathData const & def, MathData const & display)
: InsetMathNest(optionals + 3), numargs_(numargs),
optionals_(optionals), optionalValues_(optionalValues),
- type_(type)
+ type_(type), editing_(false), lookOutdated_(true)
{
initMath();
cell(optIdx(i)) = optionalValues_[i];
cell(defIdx()) = def;
cell(displayIdx()) = display;
+
+ updateLook();
}
MathMacroTemplate::MathMacroTemplate(docstring const & str)
: InsetMathNest(3), numargs_(0), optionals_(0),
- type_(MacroTypeNewcommand)
+ type_(MacroTypeNewcommand), editing_(false), lookOutdated_(true)
{
initMath();
return;
}
operator=( *(ar[0]->asMacroTemplate()) );
+
+ updateLook();
}
redefinition_ = mc.get(name()) != 0;
}
+
+void MathMacroTemplate::updateLook() const
+{
+ lookOutdated_ = true;
+}
+
+void MathMacroTemplate::createLook() const
+{
+ look_.clear();
+
+ // \foo
+ look_.push_back(MathAtom(new InsetLabelBox(
+ editing_ ? _("name") : docstring(),
+ *this,
+ false)));
+ MathData & nameData = look_[look_.size() - 1].nucleus()->cell(0);
+ nameData.push_back(MathAtom(new InsetNameWrapper(&cell(0), *this)));
+
+ // [#1][#2]
+ int i = 0;
+ if (optionals_ > 0) {
+ look_.push_back(MathAtom(new InsetLabelBox(
+ editing_ ? _("optional") : docstring(),
+ *this,
+ false)));
+ MathData & optData = look_[look_.size() - 1].nucleus()->cell(0);
+
+ for (; i < optionals_; ++i) {
+ optData.push_back(MathAtom(new InsetMathChar('[')));
+ optData.push_back(MathAtom(new InsetMathWrapper(&cell(1 + i))));
+ optData.push_back(MathAtom(new InsetMathChar(']')));
+ }
+ }
+
+ // {#3}{#4}
+ for (; i < numargs_; ++i) {
+ MathData arg;
+ arg.push_back(MathAtom(new MathMacroArgument(i + 1)));
+ look_.push_back(MathAtom(new InsetMathBrace(arg)));
+ }
+
+ // :=
+ look_.push_back(MathAtom(new InsetMathChar(':')));
+ look_.push_back(MathAtom(new InsetMathChar('=')));
+
+ // definition
+ look_.push_back(
+ MathAtom(new InsetLabelBox(
+ MathAtom(new InsetMathWrapper(&cell(defIdx()))),
+ editing_ ? from_ascii("TeX") : docstring(),
+ *this,
+ true)));
+
+ // display
+ if (editing_ || !cell(displayIdx()).empty()) {
+ look_.push_back(
+ MathAtom(new InsetLabelBox(
+ MathAtom(new InsetMathWrapper(&cell(displayIdx()))),
+ editing_ ? from_ascii("LyX") : docstring(),
+ *this,
+ true)));
+ }
+}
+
void MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const
{
FontSetChanger dummy1(mi.base, from_ascii("mathnormal"));
StyleChanger dummy2(mi.base, LM_ST_TEXT);
- // tiny font for sublabels
- FontInfo slFont = sane_font;
- slFont.decSize();
- slFont.decSize();
- slFont.decSize();
- slFont.decSize();
- Dimension slDim;
- bool edit = editing(mi.base.bv);
-
// valid macro?
MacroData const * macro = 0;
if (validName()) {
// updateToContext() - avoids another lookup
redefinition_ = macro != 0;
}
-
- // create label "{#1}{#2}:="
- label_.clear();
- int i = 0;
- for (; i < optionals_; ++i) {
- label_.push_back(MathAtom(new InsetMathChar('[')));
- label_.push_back(MathAtom(new InsetMathWrapper(&cell(1 + i))));
- label_.push_back(MathAtom(new InsetMathChar(']')));
+
+ // new edit mode?
+ bool realEditing = editing(mi.base.bv);
+ if (editing_ != realEditing) {
+ editing_ = realEditing;
+ lookOutdated_ = true;
}
- for (; i < numargs_; ++i) {
- MathData arg;
- arg.push_back(MathAtom(new MathMacroArgument(i + 1)));
- label_.push_back(MathAtom(new InsetMathBrace(arg)));
+
+ // update look?
+ if (lookOutdated_) {
+ lookOutdated_ = false;
+ createLook();
}
- label_.push_back(MathAtom(new InsetMathChar(':')));
- label_.push_back(MathAtom(new InsetMathChar('=')));
-
- // do metrics
- if (macro)
- macro->lock();
-
- Dimension dim0;
- Dimension labeldim;
- Dimension defdim;
- Dimension dspdim;
- cell(0).metrics(mi, dim0);
- label_.metrics(mi, labeldim);
- cell(defIdx()).metrics(mi, defdim);
- cell(displayIdx()).metrics(mi, dspdim);
-
+ /// metrics for inset contents
if (macro)
- macro->unlock();
-
- // calculate metrics taking all cells and labels into account
- dim.wid = 2 + mathed_string_width(mi.base.font, from_ascii("\\")) +
- dim0.width() +
- labeldim.width() +
- defdim.width() + 10;
-
- dim.asc = dim0.ascent();
- dim.des = dim0.descent();
-
- dim.asc = max(dim.asc, labeldim.ascent());
- dim.des = max(dim.des, labeldim.descent());
-
- dim.asc = max(dim.asc, defdim.ascent());
- dim.des = max(dim.des, defdim.descent());
-
- // hide empty display cells if not edited
- if (edit || !cell(displayIdx()).empty()) {
- // display
- dim.asc = max(dim.asc, dspdim.ascent());
- dim.des = max(dim.des, dspdim.descent());
- if (edit) {
- mathed_string_dim(slFont, from_ascii("LyX"), slDim);
- dim.wid += max(dspdim.width(), slDim.wid) + 8;
- } else
- dim.wid += dspdim.width() + 8;
- }
+ macro->lock();
- // make the name cell vertically centered, and 5 pixel lines margin
- int real_asc = dim.asc - dim0.ascent() / 2;
- int real_des = dim.des + dim0.ascent() / 2;
- dim.asc = max(real_asc, real_des) + dim0.ascent() / 2 + 5;
- dim.des = max(real_asc, real_des) - dim0.ascent() / 2 + 5;
- cellDim_ = dim;
+ // first phase, premetric:
+ premetrics_ = true;
+ look_.metrics(mi, dim);
+ labelBoxAscent_ = dim.asc;
+ labelBoxDescent_ = dim.des;
- // add sublabels below
- if (edit) {
- mathed_string_dim(slFont, from_ascii("Mg"), slDim);
- dim.des += 2 + slDim.asc + slDim.des + 2;
+ // second phase, main metric:
+ premetrics_ = false;
+ look_.metrics(mi, dim);
+
+ // metrics for invisible display box
+ if (!editing_ && cell(displayIdx()).empty()) {
+ Dimension ddim;
+ cell(displayIdx()).metrics(mi, ddim);
}
+ if (macro)
+ macro->unlock();
+
+ dim.wid += 6;
+ dim.des += 2;
+ dim.asc += 2;
+
setDimCache(mi, dim);
}
setPosCache(pi, x, y);
Dimension const dim = dimension(*pi.base.bv);
-
- // sublabel font
- FontInfo slFont = sane_font;
- slFont.setColor(Color_command);
- slFont.decSize();
- slFont.decSize();
- slFont.decSize();
- slFont.decSize();
- bool edit = editing(pi.base.bv);
-
- // sublabel position
- Dimension slDim;
- mathed_string_dim(slFont, from_ascii("Mg"), slDim);
- int const sly = y + cellDim_.des + slDim.asc + 2;
-
- // create fonts
- bool valid = validMacro();
- FontInfo font = pi.base.font;
- if (valid)
- font.setColor(Color_latex);
- else
- font.setColor(Color_error);
// draw outer frame
int const a = y - dim.asc + 1;
int const w = dim.wid - 2;
int const h = dim.height() - 2;
pi.pain.rectangle(x, a, w, h, Color_mathframe);
- x += 4;
-
- // draw backslash
- pi.pain.text(x, y, from_ascii("\\"), font);
- x += mathed_string_width(font, from_ascii("\\"));
-
- // draw name
- PainterInfo namepi = pi;
- namepi.base.font = font;
- cell(0).draw(namepi, x, y);
- x += cell(0).dimension(*pi.base.bv).width();
-
- // draw label
- label_.draw(pi, x, y);
- x += label_.dimension(*pi.base.bv).width();
-
- // draw definition
- cell(defIdx()).draw(pi, x + 2, y);
- int const w1 = cell(defIdx()).dimension(*pi.base.bv).width();
- pi.pain.rectangle(x, y - dim.ascent() + 3, w1 + 4, cellDim_.height() - 6,
- Color_mathline);
- x += w1 + 8;
-
- // hide empty display cells if not edited
- if (edit || !cell(displayIdx()).empty()) {
- // draw sublabel
- if (edit)
- pi.pain.text(x + 2, sly, from_ascii("LyX"), slFont);
-
- // draw display
- cell(displayIdx()).draw(pi, x + 2, y);
- int const w2 = cell(displayIdx()).dimension(*pi.base.bv).width();
- pi.pain.rectangle(x, y - dim.ascent() + 3, w2 + 4, cellDim_.height() - 6,
- Color_mathline);
- } else {
- // at least update the coord cache if not drawn
- cell(displayIdx()).setXY(*pi.base.bv, x + 2, y);
+
+ // just to be sure: set some dummy values for coord cache
+ for (idx_type i = 0; i < nargs(); ++i) {
+ cell(i).setXY(*pi.base.bv, x, y);
}
+
+ // draw contents
+ look_.draw(pi, x + 3, y);
}
void MathMacroTemplate::edit(Cursor & cur, bool left)
{
+ updateLook();
cur.updateFlags(Update::Force);
InsetMathNest::edit(cur, left);
}
+Inset * MathMacroTemplate::editXY(Cursor & cur, int x, int y)
+{
+ Inset * ret = InsetMathNest::editXY(cur, x, y);
+/* if (!editing_ && editing(cur.bv())) {
+
+ cur.updateFlags(Update::Force);
+ }*/
+ return ret;
+}
+
+
bool MathMacroTemplate::notifyCursorLeaves(Cursor & cur)
{
+ updateLook();
cur.updateFlags(Update::Force);
return InsetMathNest::notifyCursorLeaves(cur);
}
it.cell().erase(it.pos());
}
}
+
+ updateLook();
}
if (arg->number() >= from + 1)
arg->setNumber(arg->number() + by);
}
+
+ updateLook();
}
fixMacroInstancesAddRemove(dit, name(), pos, true);
}
}
+
+ updateLook();
}
fixMacroInstancesAddRemove(dit, name(), pos, false);
}
}
+
+ updateLook();
}
dit.top().forwardPos();
fixMacroInstancesOptional(dit, name(), optionals_);
}
+
+ updateLook();
}
dit.top().forwardPos();
fixMacroInstancesOptional(dit, name(), optionals_);
}
+
+ updateLook();
}
return;
}
operator=( *(ar[0]->asMacroTemplate()) );
+
+ updateLook();
}