* proper labels under the holes in macro templates during editing

* The labels can easily be changed. In fact the whole layout can easily be changed because it's modular. So nothing is final yet...


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@22271 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Stefan Schimanski 2007-12-23 01:25:51 +00:00
parent e5bd44aadc
commit dfb41a2744
2 changed files with 356 additions and 143 deletions

View File

@ -24,6 +24,7 @@
#include "MathMacroArgument.h" #include "MathMacroArgument.h"
#include "Buffer.h" #include "Buffer.h"
#include "BufferView.h"
#include "Color.h" #include "Color.h"
#include "Cursor.h" #include "Cursor.h"
#include "support/debug.h" #include "support/debug.h"
@ -51,6 +52,134 @@ namespace lyx {
using support::bformat; 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 { class InsetMathWrapper : public InsetMath {
public: public:
@ -89,9 +218,69 @@ void InsetMathWrapper::draw(PainterInfo & pi, int x, int y) const
} }
///////////////////////////////////////////////////////////////////////
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() MathMacroTemplate::MathMacroTemplate()
: InsetMathNest(3), numargs_(0), optionals_(0), : InsetMathNest(3), numargs_(0), optionals_(0),
type_(MacroTypeNewcommand) type_(MacroTypeNewcommand), editing_(false), lookOutdated_(true)
{ {
initMath(); initMath();
} }
@ -103,7 +292,7 @@ MathMacroTemplate::MathMacroTemplate(docstring const & name, int numargs,
MathData const & def, MathData const & display) MathData const & def, MathData const & display)
: InsetMathNest(optionals + 3), numargs_(numargs), : InsetMathNest(optionals + 3), numargs_(numargs),
optionals_(optionals), optionalValues_(optionalValues), optionals_(optionals), optionalValues_(optionalValues),
type_(type) type_(type), editing_(false), lookOutdated_(true)
{ {
initMath(); initMath();
@ -117,12 +306,14 @@ MathMacroTemplate::MathMacroTemplate(docstring const & name, int numargs,
cell(optIdx(i)) = optionalValues_[i]; cell(optIdx(i)) = optionalValues_[i];
cell(defIdx()) = def; cell(defIdx()) = def;
cell(displayIdx()) = display; cell(displayIdx()) = display;
updateLook();
} }
MathMacroTemplate::MathMacroTemplate(docstring const & str) MathMacroTemplate::MathMacroTemplate(docstring const & str)
: InsetMathNest(3), numargs_(0), optionals_(0), : InsetMathNest(3), numargs_(0), optionals_(0),
type_(MacroTypeNewcommand) type_(MacroTypeNewcommand), editing_(false), lookOutdated_(true)
{ {
initMath(); initMath();
@ -137,6 +328,8 @@ MathMacroTemplate::MathMacroTemplate(docstring const & str)
return; return;
} }
operator=( *(ar[0]->asMacroTemplate()) ); operator=( *(ar[0]->asMacroTemplate()) );
updateLook();
} }
@ -157,21 +350,76 @@ void MathMacroTemplate::updateToContext(MacroContext const & mc) const
redefinition_ = mc.get(name()) != 0; 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 void MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const
{ {
FontSetChanger dummy1(mi.base, from_ascii("mathnormal")); FontSetChanger dummy1(mi.base, from_ascii("mathnormal"));
StyleChanger dummy2(mi.base, LM_ST_TEXT); 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? // valid macro?
MacroData const * macro = 0; MacroData const * macro = 0;
if (validName()) { if (validName()) {
@ -180,79 +428,46 @@ void MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const
// updateToContext() - avoids another lookup // updateToContext() - avoids another lookup
redefinition_ = macro != 0; 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(']')));
}
for (; i < numargs_; ++i) {
MathData arg;
arg.push_back(MathAtom(new MathMacroArgument(i + 1)));
label_.push_back(MathAtom(new InsetMathBrace(arg)));
}
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); // new edit mode?
label_.metrics(mi, labeldim); bool realEditing = editing(mi.base.bv);
cell(defIdx()).metrics(mi, defdim); if (editing_ != realEditing) {
cell(displayIdx()).metrics(mi, dspdim); editing_ = realEditing;
lookOutdated_ = true;
}
// update look?
if (lookOutdated_) {
lookOutdated_ = false;
createLook();
}
/// metrics for inset contents
if (macro)
macro->lock();
// first phase, premetric:
premetrics_ = true;
look_.metrics(mi, dim);
labelBoxAscent_ = dim.asc;
labelBoxDescent_ = dim.des;
// 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) if (macro)
macro->unlock(); 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.wid += 6;
dim.des = max(dim.des, labeldim.descent()); dim.des += 2;
dim.asc += 2;
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;
}
// 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;
// add sublabels below
if (edit) {
mathed_string_dim(slFont, from_ascii("Mg"), slDim);
dim.des += 2 + slDim.asc + slDim.des + 2;
}
setDimCache(mi, dim); setDimCache(mi, dim);
} }
@ -265,84 +480,45 @@ void MathMacroTemplate::draw(PainterInfo & pi, int x, int y) const
setPosCache(pi, x, y); setPosCache(pi, x, y);
Dimension const dim = dimension(*pi.base.bv); 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 // draw outer frame
int const a = y - dim.asc + 1; int const a = y - dim.asc + 1;
int const w = dim.wid - 2; int const w = dim.wid - 2;
int const h = dim.height() - 2; int const h = dim.height() - 2;
pi.pain.rectangle(x, a, w, h, Color_mathframe); pi.pain.rectangle(x, a, w, h, Color_mathframe);
x += 4;
// just to be sure: set some dummy values for coord cache
// draw backslash for (idx_type i = 0; i < nargs(); ++i) {
pi.pain.text(x, y, from_ascii("\\"), font); cell(i).setXY(*pi.base.bv, x, y);
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);
} }
// draw contents
look_.draw(pi, x + 3, y);
} }
void MathMacroTemplate::edit(Cursor & cur, bool left) void MathMacroTemplate::edit(Cursor & cur, bool left)
{ {
updateLook();
cur.updateFlags(Update::Force); cur.updateFlags(Update::Force);
InsetMathNest::edit(cur, left); 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) bool MathMacroTemplate::notifyCursorLeaves(Cursor & cur)
{ {
updateLook();
cur.updateFlags(Update::Force); cur.updateFlags(Update::Force);
return InsetMathNest::notifyCursorLeaves(cur); return InsetMathNest::notifyCursorLeaves(cur);
} }
@ -364,6 +540,8 @@ void MathMacroTemplate::removeArguments(Cursor & cur, int from, int to) {
it.cell().erase(it.pos()); it.cell().erase(it.pos());
} }
} }
updateLook();
} }
@ -377,6 +555,8 @@ void MathMacroTemplate::shiftArguments(size_t from, int by) {
if (arg->number() >= from + 1) if (arg->number() >= from + 1)
arg->setNumber(arg->number() + by); arg->setNumber(arg->number() + by);
} }
updateLook();
} }
@ -491,6 +671,8 @@ void MathMacroTemplate::insertParameter(Cursor & cur, int pos, bool greedy)
fixMacroInstancesAddRemove(dit, name(), pos, true); fixMacroInstancesAddRemove(dit, name(), pos, true);
} }
} }
updateLook();
} }
@ -530,6 +712,8 @@ void MathMacroTemplate::removeParameter(Cursor & cur, int pos, bool greedy)
fixMacroInstancesAddRemove(dit, name(), pos, false); fixMacroInstancesAddRemove(dit, name(), pos, false);
} }
} }
updateLook();
} }
@ -549,6 +733,8 @@ void MathMacroTemplate::makeOptional(Cursor & cur) {
dit.top().forwardPos(); dit.top().forwardPos();
fixMacroInstancesOptional(dit, name(), optionals_); fixMacroInstancesOptional(dit, name(), optionals_);
} }
updateLook();
} }
@ -579,6 +765,8 @@ void MathMacroTemplate::makeNonOptional(Cursor & cur) {
dit.top().forwardPos(); dit.top().forwardPos();
fixMacroInstancesOptional(dit, name(), optionals_); fixMacroInstancesOptional(dit, name(), optionals_);
} }
updateLook();
} }
@ -735,6 +923,8 @@ void MathMacroTemplate::read(Buffer const &, Lexer & lex)
return; return;
} }
operator=( *(ar[0]->asMacroTemplate()) ); operator=( *(ar[0]->asMacroTemplate()) );
updateLook();
} }

View File

@ -40,6 +40,8 @@ public:
/// ///
void edit(Cursor & cur, bool left); void edit(Cursor & cur, bool left);
/// ///
Inset * editXY(Cursor & cur, int x, int y);
///
bool notifyCursorLeaves(Cursor & cur); bool notifyCursorLeaves(Cursor & cur);
/// ///
void read(Buffer const &, Lexer & lex); void read(Buffer const &, Lexer & lex);
@ -125,8 +127,10 @@ private:
idx_type optIdx(idx_type n) const { return n + 1; } idx_type optIdx(idx_type n) const { return n + 1; }
/// ///
idx_type displayIdx() const { return optionals_ + 2; } idx_type displayIdx() const { return optionals_ + 2; }
/// The label with some holes to edit ///
mutable MathData label_; void updateLook() const;
/// The representation of the macro tempalte, with some holes to edit
mutable MathData look_;
/// ///
mutable int numargs_; mutable int numargs_;
/// ///
@ -140,7 +144,26 @@ private:
/// defined before already? /// defined before already?
mutable bool redefinition_; mutable bool redefinition_;
/// ///
mutable Dimension cellDim_; mutable bool editing_;
///
void createLook() const;
///
mutable bool lookOutdated_;
/// true if in pre-calculations of metrics to get height of boxes
mutable bool premetrics_;
///
mutable int labelBoxAscent_;
///
mutable int labelBoxDescent_;
private:
friend class InsetLabelBox;
///
bool premetrics() const { return premetrics_; }
///
int commonLabelBoxAscent() const { return labelBoxAscent_; }
///
int commonLabelBoxDescent() const { return labelBoxDescent_; }
}; };