fix bug 2558: hspace support in math

The basic idea was to reuse the corresponding text space inset in the same
fashion as is already done for references. The dialog displays a different
selection for math than for text. If wanted, the additional spaces could
also be enabled for text, but that would be a file format change.
Constructs like \hspace{\mylengthvariable} that are not supported are
treated by the math parser as ERT as before.

For reasons I don't know the context menu does not work, but this is not so
important IMHO (since a left click opens the dialog).


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@27954 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Georg Baum 2008-12-22 18:12:32 +00:00
parent df8bb4edcd
commit ac1fd9b37f
14 changed files with 520 additions and 148 deletions

View File

@ -128,13 +128,19 @@ vref ref none
lyxnegspace space none
lyxposspace space none
! space none
negthinspace space none
negmedspace space none
negthickspace space none
, space none
thinspace space none
: space none
medspace space none
; space none
thickspace space none
enskip space none
quad space none
qquad space none
hspace space none
# styles
displaystyle style 0

View File

@ -190,6 +190,24 @@ Menuset
Item "Settings...|S" "next-inset-toggle"
End
#
# InsetMathSpace context menu
#
Menu "context-mathspace"
Item "Thin Space|T" "next-inset-modify mathspace \thinspace{}"
Item "Medium Space|M" "next-inset-modify mathspace \medspace{}"
Item "Thick Space|h" "next-inset-modify mathspace \thickspace{}"
Item "Negative Thin Space|N" "next-inset-modify mathspace \negthinspace{}"
Item "Negative Medium Space|u" "next-inset-modify mathspace \negmedspace{}"
Item "Negative Thick Space|i" "next-inset-modify mathspace \negthickspace{}"
Item "Half Quad Space (Enskip)|k" "next-inset-modify mathspace \enskip{}"
Item "Quad Space|Q" "next-inset-modify mathspace \quad{}"
Item "Double Quad Space|u" "next-inset-modify mathspace \qquad{}"
Item "Custom Length|C" "command-sequence next-inset-modify mathspace \hspace{} \length 1in; next-inset-toggle"
Separator
Item "Settings...|S" "next-inset-toggle"
End
#
# InsetVSpace context menu
#

View File

@ -330,12 +330,17 @@ Inset * createInsetHelper(Buffer & buf, FuncRequest const & cmd)
break;
}
InsetSpaceParams isp;
// The tests for isp.math might be disabled after a file format change
if (name == "normal")
isp.kind = InsetSpaceParams::NORMAL;
else if (name == "protected")
isp.kind = InsetSpaceParams::PROTECTED;
else if (name == "thin")
isp.kind = InsetSpaceParams::THIN;
else if (isp.math && name == "med")
isp.kind = InsetSpaceParams::MEDIUM;
else if (isp.math && name == "thick")
isp.kind = InsetSpaceParams::THICK;
else if (name == "quad")
isp.kind = InsetSpaceParams::QUAD;
else if (name == "qquad")
@ -346,6 +351,10 @@ Inset * createInsetHelper(Buffer & buf, FuncRequest const & cmd)
isp.kind = InsetSpaceParams::ENSKIP;
else if (name == "negthinspace")
isp.kind = InsetSpaceParams::NEGTHIN;
else if (isp.math && name == "negmedspace")
isp.kind = InsetSpaceParams::NEGMEDIUM;
else if (isp.math && name == "negthickspace")
isp.kind = InsetSpaceParams::NEGTHICK;
else if (name == "hfill")
isp.kind = InsetSpaceParams::HFILL;
else if (name == "hfill*")

View File

@ -35,9 +35,10 @@ using namespace std;
namespace lyx {
namespace frontend {
GuiHSpace::GuiHSpace(GuiView & lv)
: GuiDialog(lv, "space", qt_("Horizontal Space Settings"))
GuiHSpace::GuiHSpace(GuiView & lv, bool math)
: GuiDialog(lv, math ? "mathspace" : "space", qt_("Horizontal Space Settings"))
{
params_.math = math;
setupUi(this);
connect(okPB, SIGNAL(clicked()), this, SLOT(slotOK()));
@ -86,8 +87,23 @@ void GuiHSpace::change_adaptor()
}
void GuiHSpace::setMath(bool custom)
{
valueLE->setEnabled(custom);
unitCO->setEnabled(custom);
fillPatternCO->setEnabled(false);
keepCB->setToolTip(qt_("Insert the spacing even after a line break"));
keepCB->setEnabled(false);
}
void GuiHSpace::enableWidgets(int selection)
{
if (params_.math) {
setMath(selection == 9);
changed();
return;
}
valueLE->setEnabled(selection == 7);
unitCO->setEnabled(selection == 7);
fillPatternCO->setEnabled(selection == 6);
@ -120,6 +136,33 @@ static void setWidgetsFromHSpace(InsetSpaceParams const & params,
QCheckBox * keep,
QComboBox * fillPattern)
{
spacing->clear();
if (params.math) {
spacing->addItem(qt_("Thin space"));
spacing->addItem(qt_("Medium space"));
spacing->addItem(qt_("Thick space"));
spacing->addItem(qt_("Negative thin space"));
spacing->addItem(qt_("Negative medium space"));
spacing->addItem(qt_("Negative thick space"));
spacing->addItem(qt_("Half Quad (0.5 em)"));
spacing->addItem(qt_("Quad (1 em)"));
spacing->addItem(qt_("Double Quad (2 em)"));
spacing->addItem(qt_("Custom"));
keep->setEnabled(false);
fillPattern->setEnabled(false);
} else {
spacing->addItem(qt_("Inter-word space"));
spacing->addItem(qt_("Thin space"));
spacing->addItem(qt_("Negative thin space"));
spacing->addItem(qt_("Half Quad (0.5 em)"));
spacing->addItem(qt_("Quad (1 em)"));
spacing->addItem(qt_("Double Quad (2 em)"));
spacing->addItem(qt_("Horizontal Fill"));
spacing->addItem(qt_("Custom"));
keep->setEnabled(true);
fillPattern->setEnabled(true);
}
int item = 0;
int pattern = 0;
bool protect = false;
@ -129,64 +172,76 @@ static void setWidgetsFromHSpace(InsetSpaceParams const & params,
break;
case InsetSpaceParams::PROTECTED:
item = 0;
protect = true;
protect = !params.math;
break;
case InsetSpaceParams::THIN:
item = params.math ? 0 : 1;
break;
case InsetSpaceParams::MEDIUM:
item = 1;
break;
case InsetSpaceParams::THICK:
item = params.math ? 2 : 1;
break;
case InsetSpaceParams::NEGTHIN:
item = 2;
item = params.math ? 3 : 2;
break;
case InsetSpaceParams::NEGMEDIUM:
item = params.math ? 4 : 2;
break;
case InsetSpaceParams::NEGTHICK:
item = params.math ? 5 : 2;
break;
case InsetSpaceParams::ENSKIP:
item = 3;
item = params.math ? 6 : 3;
break;
case InsetSpaceParams::ENSPACE:
item = 3;
protect = true;
item = params.math ? 6 : 3;
protect = !params.math;
break;
case InsetSpaceParams::QUAD:
item = 4;
item = params.math ? 7 : 4;
break;
case InsetSpaceParams::QQUAD:
item = 5;
item = params.math ? 8 : 5;
break;
case InsetSpaceParams::HFILL:
item = 6;
item = params.math ? 3 : 6;
break;
case InsetSpaceParams::HFILL_PROTECTED:
item = 6;
protect = true;
item = params.math ? 3 : 6;
protect = !params.math;
break;
case InsetSpaceParams::DOTFILL:
item = 6;
item = params.math ? 3 : 6;
pattern = 1;
break;
case InsetSpaceParams::HRULEFILL:
item = 6;
item = params.math ? 3 : 6;
pattern = 2;
break;
case InsetSpaceParams::LEFTARROWFILL:
item = 6;
item = params.math ? 3 : 6;
pattern = 3;
break;
case InsetSpaceParams::RIGHTARROWFILL:
item = 6;
item = params.math ? 3 : 6;
pattern = 4;
break;
case InsetSpaceParams::UPBRACEFILL:
item = 6;
item = params.math ? 3 : 6;
pattern = 5;
break;
case InsetSpaceParams::DOWNBRACEFILL:
item = 6;
item = params.math ? 3 : 6;
pattern = 6;
break;
case InsetSpaceParams::CUSTOM:
item = 7;
item = params.math ? 9 : 7;
break;
case InsetSpaceParams::CUSTOM_PROTECTED:
item = 7;
protect = true;
item = params.math ? 9 : 7;
protect = !params.math;
break;
}
spacing->setCurrentIndex(item);
@ -195,7 +250,7 @@ static void setWidgetsFromHSpace(InsetSpaceParams const & params,
Length::UNIT default_unit =
(lyxrc.default_papersize > 3) ? Length::CM : Length::IN;
if (item == 7)
if (item == (params.math ? 9 : 7))
lengthToWidgets(value, unit, params.length, default_unit);
else
lengthToWidgets(value, unit, "", default_unit);
@ -203,9 +258,28 @@ static void setWidgetsFromHSpace(InsetSpaceParams const & params,
static InsetSpaceParams setHSpaceFromWidgets(int spacing,
QLineEdit * value, LengthCombo * unit, bool keep, int fill)
QLineEdit * value, LengthCombo * unit, bool keep, int fill, bool math)
{
InsetSpaceParams params;
InsetSpaceParams params(math);
if (math) {
switch (spacing) {
case 0: params.kind = InsetSpaceParams::THIN; break;
case 1: params.kind = InsetSpaceParams::MEDIUM; break;
case 2: params.kind = InsetSpaceParams::THICK; break;
case 3: params.kind = InsetSpaceParams::NEGTHIN; break;
case 4: params.kind = InsetSpaceParams::NEGMEDIUM; break;
case 5: params.kind = InsetSpaceParams::NEGTHICK; break;
case 6: params.kind = InsetSpaceParams::ENSKIP; break;
case 7: params.kind = InsetSpaceParams::QUAD; break;
case 8: params.kind = InsetSpaceParams::QQUAD; break;
case 9:
params.kind = InsetSpaceParams::CUSTOM;
params.length = Length(widgetsToLength(value, unit));
break;
}
return params;
}
switch (spacing) {
case 0:
if (keep)
@ -265,7 +339,7 @@ void GuiHSpace::applyView()
{
params_ = setHSpaceFromWidgets(spacingCO->currentIndex(),
valueLE, unitCO, keepCB->isChecked(),
fillPatternCO->currentIndex());
fillPatternCO->currentIndex(), params_.math);
}
@ -279,7 +353,11 @@ void GuiHSpace::updateContents()
bool GuiHSpace::initialiseParams(string const & data)
{
bool const math = params_.math;
InsetSpace::string2params(data, params_);
params_.math = math;
if (params_.math)
setMath(params_.kind == InsetSpaceParams::CUSTOM);
setButtonsValid(true);
return true;
}
@ -287,7 +365,7 @@ bool GuiHSpace::initialiseParams(string const & data)
void GuiHSpace::clearParams()
{
params_ = InsetSpaceParams();
params_ = InsetSpaceParams(params_.math);
}
@ -299,11 +377,15 @@ void GuiHSpace::dispatchParams()
bool GuiHSpace::isValid()
{
return spacingCO->currentIndex() != 7 || !valueLE->text().isEmpty();
return spacingCO->currentIndex() != (params_.math ? 9 : 7)
|| !valueLE->text().isEmpty();
}
Dialog * createGuiHSpace(GuiView & lv) { return new GuiHSpace(lv); }
Dialog * createGuiMathHSpace(GuiView & lv) { return new GuiHSpace(lv, true); }
Dialog * createGuiTextHSpace(GuiView & lv) { return new GuiHSpace(lv, false); }
} // namespace frontend

View File

@ -24,7 +24,7 @@ class GuiHSpace : public GuiDialog, public Ui::HSpaceUi
Q_OBJECT
public:
GuiHSpace(GuiView & lv);
GuiHSpace(GuiView & lv, bool math);
private Q_SLOTS:
///
@ -35,6 +35,8 @@ private Q_SLOTS:
void patternChanged();
private:
///
void setMath(bool custom);
/// Apply from dialog
void applyView();
/// Update the dialog

View File

@ -2068,8 +2068,9 @@ bool GuiView::dispatch(FuncRequest const & cmd)
Inset * inset = getOpenInset(name);
if (inset) {
// put cursor in front of inset.
if (!view()->setCursorFromInset(inset))
if (!view()->setCursorFromInset(inset)) {
LASSERT(false, break);
}
// useful if we are called from a dialog.
view()->cursor().beginUndoGroup();
@ -2289,7 +2290,7 @@ char const * const dialognames[] = {
"aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
"citation", "document", "errorlist", "ert", "external", "file",
"findreplace", "float", "graphics", "include", "index", "info", "nomenclature", "label", "log",
"mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
"mathdelimiter", "mathmatrix", "mathspace", "note", "paragraph", "prefs", "print",
"ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
#ifdef HAVE_LIBAIKSAURUS
@ -2470,12 +2471,12 @@ Dialog * createGuiERT(GuiView & lv);
Dialog * createGuiExternal(GuiView & lv);
Dialog * createGuiFloat(GuiView & lv);
Dialog * createGuiGraphics(GuiView & lv);
Dialog * createGuiHSpace(GuiView & lv);
Dialog * createGuiInclude(GuiView & lv);
Dialog * createGuiInfo(GuiView & lv);
Dialog * createGuiLabel(GuiView & lv);
Dialog * createGuiListings(GuiView & lv);
Dialog * createGuiLog(GuiView & lv);
Dialog * createGuiMathHSpace(GuiView & lv);
Dialog * createGuiMathMatrix(GuiView & lv);
Dialog * createGuiNomenclature(GuiView & lv);
Dialog * createGuiNote(GuiView & lv);
@ -2492,6 +2493,7 @@ Dialog * createGuiSymbols(GuiView & lv);
Dialog * createGuiTabularCreate(GuiView & lv);
Dialog * createGuiTabular(GuiView & lv);
Dialog * createGuiTexInfo(GuiView & lv);
Dialog * createGuiTextHSpace(GuiView & lv);
Dialog * createGuiToc(GuiView & lv);
Dialog * createGuiThesaurus(GuiView & lv);
Dialog * createGuiHyperlink(GuiView & lv);
@ -2552,6 +2554,8 @@ Dialog * GuiView::build(string const & name)
return createGuiViewSource(*this);
if (name == "mathdelimiter")
return createGuiDelimiter(*this);
if (name == "mathspace")
return createGuiMathHSpace(*this);
if (name == "mathmatrix")
return createGuiMathMatrix(*this);
if (name == "note")
@ -2567,7 +2571,7 @@ Dialog * GuiView::build(string const & name)
if (name == "sendto")
return createGuiSendTo(*this);
if (name == "space")
return createGuiHSpace(*this);
return createGuiTextHSpace(*this);
if (name == "spellchecker")
return createGuiSpellchecker(*this);
if (name == "symbols")

View File

@ -79,46 +79,6 @@
<property name="toolTip" >
<string>Supported spacing types</string>
</property>
<item>
<property name="text" >
<string>Inter-word space</string>
</property>
</item>
<item>
<property name="text" >
<string>Thin space</string>
</property>
</item>
<item>
<property name="text" >
<string>Negative thin space</string>
</property>
</item>
<item>
<property name="text" >
<string>Half Quad (0.5 em)</string>
</property>
</item>
<item>
<property name="text" >
<string>Quad (1 em)</string>
</property>
</item>
<item>
<property name="text" >
<string>Double Quad (2 em)</string>
</property>
</item>
<item>
<property name="text" >
<string>Horizontal Fill</string>
</property>
</item>
<item>
<property name="text" >
<string>Custom</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0" >

View File

@ -20,6 +20,7 @@
#include "Dimension.h"
#include "FuncRequest.h"
#include "FuncStatus.h"
#include "LaTeXFeatures.h"
#include "Length.h"
#include "Lexer.h"
#include "MetricsInfo.h"
@ -28,6 +29,7 @@
#include "support/debug.h"
#include "support/docstream.h"
#include "support/gettext.h"
#include "support/lassert.h"
#include "support/lstrings.h"
#include "frontends/Application.h"
@ -75,6 +77,12 @@ docstring InsetSpace::toolTip(BufferView const &, int, int) const
case InsetSpaceParams::THIN:
message = _("Thin Space");
break;
case InsetSpaceParams::MEDIUM:
message = _("Medium Space");
break;
case InsetSpaceParams::THICK:
message = _("Thick Space");
break;
case InsetSpaceParams::QUAD:
message = _("Quad Space");
break;
@ -90,6 +98,12 @@ docstring InsetSpace::toolTip(BufferView const &, int, int) const
case InsetSpaceParams::NEGTHIN:
message = _("Negative Thin Space");
break;
case InsetSpaceParams::NEGMEDIUM:
message = _("Negative Mwedium Space");
break;
case InsetSpaceParams::NEGTHICK:
message = _("Negative Thick Space");
break;
case InsetSpaceParams::HFILL:
message = _("Horizontal Fill");
break;
@ -131,10 +145,13 @@ void InsetSpace::doDispatch(Cursor & cur, FuncRequest & cmd)
{
switch (cmd.action) {
case LFUN_INSET_MODIFY: {
case LFUN_INSET_MODIFY:
string2params(to_utf8(cmd.argument()), params_);
break;
}
case LFUN_INSET_DIALOG_UPDATE:
cur.bv().updateDialog("space", params2string(params()));
break;
case LFUN_MOUSE_RELEASE:
if (!cur.selection() && cmd.button() == mouse_button::button1)
@ -159,6 +176,8 @@ bool InsetSpace::getStatus(Cursor & cur, FuncRequest const & cmd,
string2params(to_utf8(cmd.argument()), params);
status.setOnOff(params_.kind == params.kind);
}
// fall through
case LFUN_INSET_DIALOG_UPDATE:
status.setEnabled(true);
return true;
default:
@ -196,6 +215,14 @@ void InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const
case InsetSpaceParams::NEGTHIN:
dim.wid = fm.width(char_type('M')) / 6;
break;
case InsetSpaceParams::MEDIUM:
case InsetSpaceParams::NEGMEDIUM:
dim.wid = fm.width(char_type('M')) / 4;
break;
case InsetSpaceParams::THICK:
case InsetSpaceParams::NEGTHICK:
dim.wid = fm.width(char_type('M')) / 2;
break;
case InsetSpaceParams::PROTECTED:
case InsetSpaceParams::NORMAL:
dim.wid = fm.width(char_type(' '));
@ -269,12 +296,12 @@ void InsetSpace::draw(PainterInfo & pi, int x, int y) const
if (params_.kind == InsetSpaceParams::HFILL) {
pi.pain.line(x0, y1, x0, y0, Color_added_space);
pi.pain.line(x0, y2 , x1, y2, Color_added_space,
pi.pain.line(x0, y2, x1, y2, Color_added_space,
frontend::Painter::line_onoffdash);
pi.pain.line(x1, y1, x1, y0, Color_added_space);
} else if (params_.kind == InsetSpaceParams::HFILL_PROTECTED) {
pi.pain.line(x0, y1, x0, y0, Color_latex);
pi.pain.line(x0, y2 , x1, y2, Color_latex,
pi.pain.line(x0, y2, x1, y2, Color_latex,
frontend::Painter::line_onoffdash);
pi.pain.line(x1, y1, x1, y0, Color_latex);
} else if (params_.kind == InsetSpaceParams::DOTFILL) {
@ -344,6 +371,8 @@ void InsetSpace::draw(PainterInfo & pi, int x, int y) const
if (params_.kind == InsetSpaceParams::PROTECTED ||
params_.kind == InsetSpaceParams::ENSPACE ||
params_.kind == InsetSpaceParams::NEGTHIN ||
params_.kind == InsetSpaceParams::NEGMEDIUM ||
params_.kind == InsetSpaceParams::NEGTHICK ||
params_.kind == InsetSpaceParams::CUSTOM_PROTECTED)
pi.pain.lines(xp, yp, 4, Color_latex);
else
@ -364,6 +393,12 @@ void InsetSpaceParams::write(ostream & os) const
case InsetSpaceParams::THIN:
os << "\\thinspace{}";
break;
case InsetSpaceParams::MEDIUM:
os << "\\medspace{}";
break;
case InsetSpaceParams::THICK:
os << "\\thickspace{}";
break;
case InsetSpaceParams::QUAD:
os << "\\quad{}";
break;
@ -379,6 +414,12 @@ void InsetSpaceParams::write(ostream & os) const
case InsetSpaceParams::NEGTHIN:
os << "\\negthinspace{}";
break;
case InsetSpaceParams::NEGMEDIUM:
os << "\\negmedspace{}";
break;
case InsetSpaceParams::NEGTHICK:
os << "\\negthickspace{}";
break;
case InsetSpaceParams::HFILL:
os << "\\hfill{}";
break;
@ -422,12 +463,17 @@ void InsetSpaceParams::read(Lexer & lex)
string command;
lex >> command;
// The tests for math might be disabled after a file format change
if (command == "\\space{}")
kind = InsetSpaceParams::NORMAL;
else if (command == "~")
kind = InsetSpaceParams::PROTECTED;
else if (command == "\\thinspace{}")
kind = InsetSpaceParams::THIN;
else if (math && command == "\\medspace{}")
kind = InsetSpaceParams::MEDIUM;
else if (math && command == "\\thickspace{}")
kind = InsetSpaceParams::THICK;
else if (command == "\\quad{}")
kind = InsetSpaceParams::QUAD;
else if (command == "\\qquad{}")
@ -438,6 +484,10 @@ void InsetSpaceParams::read(Lexer & lex)
kind = InsetSpaceParams::ENSKIP;
else if (command == "\\negthinspace{}")
kind = InsetSpaceParams::NEGTHIN;
else if (math && command == "\\negmedspace{}")
kind = InsetSpaceParams::NEGMEDIUM;
else if (math && command == "\\negthickspace{}")
kind = InsetSpaceParams::NEGTHICK;
else if (command == "\\hfill{}")
kind = InsetSpaceParams::HFILL;
else if (command == "\\hspace*{\\fill}")
@ -492,6 +542,12 @@ int InsetSpace::latex(odocstream & os, OutputParams const & runparams) const
case InsetSpaceParams::THIN:
os << (runparams.free_spacing ? " " : "\\,");
break;
case InsetSpaceParams::MEDIUM:
os << (runparams.free_spacing ? " " : "\\:");
break;
case InsetSpaceParams::THICK:
os << (runparams.free_spacing ? " " : "\\;");
break;
case InsetSpaceParams::QUAD:
os << (runparams.free_spacing ? " " : "\\quad{}");
break;
@ -507,6 +563,12 @@ int InsetSpace::latex(odocstream & os, OutputParams const & runparams) const
case InsetSpaceParams::NEGTHIN:
os << (runparams.free_spacing ? " " : "\\negthinspace{}");
break;
case InsetSpaceParams::NEGMEDIUM:
os << (runparams.free_spacing ? " " : "\\negmedspace{}");
break;
case InsetSpaceParams::NEGTHICK:
os << (runparams.free_spacing ? " " : "\\negthickspace{}");
break;
case InsetSpaceParams::HFILL:
os << (runparams.free_spacing ? " " : "\\hfill{}");
break;
@ -592,7 +654,11 @@ int InsetSpace::docbook(odocstream & os, OutputParams const &) const
case InsetSpaceParams::PROTECTED:
case InsetSpaceParams::ENSPACE:
case InsetSpaceParams::THIN:
case InsetSpaceParams::MEDIUM:
case InsetSpaceParams::THICK:
case InsetSpaceParams::NEGTHIN:
case InsetSpaceParams::NEGMEDIUM:
case InsetSpaceParams::NEGTHICK:
os << "&nbsp;";
break;
case InsetSpaceParams::HFILL:
@ -617,6 +683,14 @@ int InsetSpace::docbook(odocstream & os, OutputParams const &) const
}
void InsetSpace::validate(LaTeXFeatures & features) const
{
if (params_.kind == InsetSpaceParams::NEGMEDIUM ||
params_.kind == InsetSpaceParams::NEGTHICK)
features.require("amsmath");
}
void InsetSpace::tocString(odocstream & os) const
{
plaintext(os, OutputParams(0));
@ -652,7 +726,14 @@ void InsetSpace::string2params(string const & in, InsetSpaceParams & params)
Lexer lex;
lex.setStream(data);
lex.setContext("InsetSpace::string2params");
lex >> "space";
lex.next();
string const name = lex.getString();
if (name == "mathspace")
params.math = true;
else {
params.math = false;
LASSERT(name == "space", /**/);
}
// There are cases, such as when we are called via getStatus() from
// Dialog::canApply(), where we are just called with "space" rather
@ -665,6 +746,8 @@ void InsetSpace::string2params(string const & in, InsetSpaceParams & params)
string InsetSpace::params2string(InsetSpaceParams const & params)
{
ostringstream data;
if (params.math)
data << "math";
data << "space" << ' ';
params.write(data);
return data.str();

View File

@ -33,16 +33,24 @@ public:
PROTECTED,
/// Thin space ('\,')
THIN,
/// Medium space ('\:')
MEDIUM,
/// Thick space ('\;')
THICK,
/// \quad (1em)
QUAD,
/// \qquad (2em)
QQUAD,
/// \enspace (0.5em unbreakable)
/// \enskip (0.5em unbreakable)
ENSPACE,
/// \enspace (0.5em breakable)
ENSKIP,
/// Negative thin space ('\negthinspace')
NEGTHIN,
/// Negative medium space ('\negmedspace')
NEGMEDIUM,
/// Negative thick space ('\negthickspace')
NEGTHICK,
/// rubber length
HFILL,
/// \hspace*{\fill}
@ -65,7 +73,7 @@ public:
CUSTOM_PROTECTED
};
///
InsetSpaceParams() : kind(NORMAL), length(Length()) {}
InsetSpaceParams(bool m = false) : kind(NORMAL), math(m) {}
///
void write(std::ostream & os) const;
///
@ -74,6 +82,11 @@ public:
Kind kind;
///
Length length;
/**
* Whether these params are to be used in mathed.
* This determines the set of valid kinds.
*/
bool math;
};
@ -99,7 +112,6 @@ public:
///
Length length() const;
private:
///
docstring toolTip(BufferView const & bv, int x, int y) const;
///
@ -116,6 +128,8 @@ private:
int plaintext(odocstream &, OutputParams const &) const;
///
int docbook(odocstream &, OutputParams const &) const;
///
void validate(LaTeXFeatures & features) const;
/// the string that is passed to the TOC
void tocString(odocstream &) const;
///
@ -137,13 +151,16 @@ private:
bool isSpace() const { return true; }
///
docstring contextMenu(BufferView const & bv, int x, int y) const;
protected:
///
Inset * clone() const { return new InsetSpace(*this); }
///
void doDispatch(Cursor & cur, FuncRequest & cmd);
public:
///
bool getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus &) const;
private:
///
InsetSpaceParams params_;
};

View File

@ -840,7 +840,6 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
break;
//case LFUN_SERVER_GET_XY:
// sprintf(dispatch_buffer, "%d %d",);
// break;
case LFUN_SERVER_SET_XY: {
@ -1055,15 +1054,15 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
case LFUN_SPACE_INSERT:
cur.recordUndoSelection();
cur.insert(MathAtom(new InsetMathSpace(from_ascii(","))));
cur.insert(MathAtom(new InsetMathSpace));
break;
case LFUN_MATH_SPACE:
cur.recordUndoSelection();
if (cmd.argument().empty())
cur.insert(MathAtom(new InsetMathSpace(from_ascii(","))));
cur.insert(MathAtom(new InsetMathSpace));
else
cur.insert(MathAtom(new InsetMathSpace(cmd.argument())));
cur.insert(MathAtom(new InsetMathSpace(to_utf8(cmd.argument()), "")));
break;
case LFUN_ERT_INSERT:
@ -1131,6 +1130,9 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
if (name == "ref") {
InsetMathRef tmp(name);
data = tmp.createDialogStr(to_utf8(name));
} else if (name == "mathspace") {
InsetMathSpace tmp;
data = tmp.createDialogStr();
}
cur.bv().showDialog(to_utf8(name), data);
break;
@ -1274,7 +1276,7 @@ bool InsetMathNest::getStatus(Cursor & cur, FuncRequest const & cmd,
// getStatus is not called with a valid reference and the
// dialog would not be applyable.
string const name = cmd.getArg(0);
flag.setEnabled(name == "ref");
flag.setEnabled(name == "ref" || name == "mathspace");
break;
}

View File

@ -12,63 +12,101 @@
#include "InsetMathSpace.h"
#include "MathData.h"
#include "MathFactory.h"
#include "MathStream.h"
#include "MathSupport.h"
#include "BufferView.h"
#include "Cursor.h"
#include "FuncRequest.h"
#include "FuncStatus.h"
#include "LaTeXFeatures.h"
#include "insets/InsetSpace.h"
#include "frontends/Application.h"
#include "frontends/Painter.h"
#include "support/lassert.h"
using namespace std;
namespace lyx {
char const * latex_mathspace[] = {
"!", "negmedspace", "negthickspace", // negative space
",", ":", ";", "quad", "qquad", // positive space
"lyxnegspace", "lyxposspace" // LyX special ("unvisible space")
};
int const nSpace = sizeof(latex_mathspace)/sizeof(char *);
namespace {
int spaceToWidth(int space)
{
switch (space) {
case 0: return 6;
case 1: return 8;
case 2: return 10;
case 3: return 6;
case 4: return 8;
case 5: return 10;
case 6: return 20;
case 7: return 40;
case 8: return -2;
case 9: return 2;
default: return 6;
}
}
struct SpaceInfo {
string name;
int width;
InsetSpaceParams::Kind kind;
bool negative;
bool visible;
bool custom;
};
SpaceInfo space_info[] = {
// name width kind negative visible custom
{"!", 6, InsetSpaceParams::NEGTHIN, true, true, false},
{"negthinspace", 6, InsetSpaceParams::NEGTHIN, true, true, false},
{"negmedspace", 8, InsetSpaceParams::NEGMEDIUM, true, true, false},
{"negthickspace", 10, InsetSpaceParams::NEGTHICK, true, true, false},
{",", 6, InsetSpaceParams::THIN, false, true, false},
{"thinspace", 6, InsetSpaceParams::THIN, false, true, false},
{":", 8, InsetSpaceParams::MEDIUM, false, true, false},
{"medspace", 8, InsetSpaceParams::MEDIUM, false, true, false},
{";", 10, InsetSpaceParams::THICK, false, true, false},
{"thickspace", 10, InsetSpaceParams::THICK, false, true, false},
{"enskip", 10, InsetSpaceParams::ENSKIP, false, true, false},
{"quad", 20, InsetSpaceParams::QUAD, false, true, false},
{"qquad", 40, InsetSpaceParams::QQUAD, false, true, false},
{"lyxnegspace", -2, InsetSpaceParams::NEGTHIN, true, false, false},
{"lyxposspace", 2, InsetSpaceParams::THIN, false, false, false},
{"hspace", 0, InsetSpaceParams::CUSTOM, false, true, true},
};
int const nSpace = sizeof(space_info)/sizeof(SpaceInfo);
int const defaultSpace = 4;
} // anon namespace
InsetMathSpace::InsetMathSpace(int sp)
: space_(sp)
InsetMathSpace::InsetMathSpace()
: space_(defaultSpace)
{
dim_.asc = 4;
dim_.des = 0;
dim_.wid = spaceToWidth(space_);
}
InsetMathSpace::InsetMathSpace(docstring const & name)
: space_(1)
InsetMathSpace::InsetMathSpace(string const & name, string const & length)
: space_(defaultSpace)
{
dim_.asc = 4;
dim_.des = 0;
for (int i = 0; i < nSpace; ++i)
if (latex_mathspace[i] == name)
if (space_info[i].name == name) {
space_ = i;
dim_.wid = spaceToWidth(space_);
break;
}
if (space_info[space_].custom) {
length_ = Length(length);
if (length_.zero() || length_.empty()) {
length_.value(1.0);
length_.unit(Length::EM);
}
}
}
InsetMathSpace::InsetMathSpace(Length const & length)
: space_(defaultSpace), length_(length)
{
for (int i = 0; i < nSpace; ++i)
if (space_info[i].name == "hspace") {
space_ = i;
break;
}
}
InsetMathSpace::~InsetMathSpace()
{
hideDialogs("mathspace", this);
}
@ -78,9 +116,16 @@ Inset * InsetMathSpace::clone() const
}
void InsetMathSpace::metrics(MetricsInfo &, Dimension & dim) const
void InsetMathSpace::metrics(MetricsInfo & mi, Dimension & dim) const
{
dim = dim_;
dim.asc = 4;
dim.des = 0;
if (space_info[space_].custom)
dim.wid = abs(length_.inPixels(
mi.base.textwidth,
mathed_char_width(mi.base.font, 'M')));
else
dim.wid = space_info[space_].width;
}
@ -88,36 +133,45 @@ void InsetMathSpace::draw(PainterInfo & pi, int x, int y) const
{
// Sadly, HP-UX CC can't handle that kind of initialization.
// XPoint p[4] = {{++x, y-3}, {x, y}, {x+width-2, y}, {x+width-2, y-3}};
if (space_ >= nSpace - 2)
if (!space_info[space_].visible)
return;
Dimension const dim = dimension(*pi.base.bv);
int xp[4];
int yp[4];
int w = dim_.wid;
int w = dim.wid;
xp[0] = ++x; yp[0] = y - 3;
xp[1] = x; yp[1] = y;
xp[2] = x + w - 2; yp[2] = y;
xp[3] = x + w - 2; yp[3] = y - 3;
pi.pain.lines(xp, yp, 4, (space_ < 3) ? Color_latex : Color_math);
pi.pain.lines(xp, yp, 4,
space_info[space_].custom ?
Color_special :
(isNegative() ? Color_latex : Color_math));
}
void InsetMathSpace::incSpace()
{
space_ = (space_ + 1) % (nSpace - 2);
dim_.wid = spaceToWidth(space_);
int const oldwidth = space_info[space_].width;
do
space_ = (space_ + 1) % nSpace;
while ((space_info[space_].width == oldwidth && !space_info[space_].custom) ||
!space_info[space_].visible);
if (space_info[space_].custom && (length_.zero() || length_.empty())) {
length_.value(1.0);
length_.unit(Length::EM);
}
}
void InsetMathSpace::validate(LaTeXFeatures & features) const
{
if (space_ >= 0 && space_< nSpace) {
if ((latex_mathspace[space_] == string("negmedspace"))
|| (latex_mathspace[space_] == string("negthickspace")))
features.require("amsmath");
}
if (space_info[space_].name == "negmedspace" ||
space_info[space_].name == "negthickspace")
features.require("amsmath");
}
@ -146,12 +200,94 @@ void InsetMathSpace::normalize(NormalStream & os) const
void InsetMathSpace::write(WriteStream & os) const
{
if (space_ >= 0 && space_ < nSpace) {
MathEnsurer ensurer(os);
os << '\\' << latex_mathspace[space_];
// no MathEnsurer - all kinds work in text and math mode
os << '\\' << space_info[space_].name.c_str();
if (space_info[space_].custom)
os << '{' << length_.asLatexString().c_str() << '}';
else
os.pendingSpace(true);
}
string const InsetMathSpace::createDialogStr() const
{
LASSERT(space_info[space_].visible, /**/);
InsetSpaceParams isp(true);
isp.kind = space_info[space_].kind;
isp.length = length_;
return InsetSpace::params2string(isp);
}
docstring InsetMathSpace::contextMenu(BufferView const &, int, int) const
{
return from_ascii("context-mathspace");
}
bool InsetMathSpace::getStatus(Cursor & cur, FuncRequest const & cmd,
FuncStatus & status) const
{
switch (cmd.action) {
// we handle these
case LFUN_INSET_MODIFY:
case LFUN_INSET_DIALOG_UPDATE:
case LFUN_MOUSE_RELEASE:
case LFUN_MOUSE_PRESS:
case LFUN_MOUSE_MOTION:
status.setEnabled(true);
return true;
default:
bool retval = InsetMath::getStatus(cur, cmd, status);
return retval;
}
}
void InsetMathSpace::doDispatch(Cursor & cur, FuncRequest & cmd)
{
switch (cmd.action) {
case LFUN_INSET_MODIFY:
if (cmd.getArg(0) == "mathspace") {
MathData ar;
if (createInsetMath_fromDialogStr(cmd.argument(), ar)) {
*this = *ar[0].nucleus()->asSpaceInset();
break;
}
}
cur.undispatched();
break;
case LFUN_INSET_DIALOG_UPDATE:
cur.bv().updateDialog("mathspace", createDialogStr());
break;
case LFUN_MOUSE_RELEASE:
if (cmd.button() == mouse_button::button1) {
string const data = createDialogStr();
cur.bv().showDialog("mathspace", data, this);
break;
}
cur.undispatched();
break;
case LFUN_MOUSE_PRESS:
case LFUN_MOUSE_MOTION:
// eat other mouse commands
break;
default:
InsetMath::doDispatch(cur, cmd);
break;
}
}
bool InsetMathSpace::isNegative() const
{
if (space_info[space_].custom)
return length_.value() < 0;
return space_info[space_].negative;
}
} // namespace lyx

View File

@ -13,6 +13,7 @@
#define MATH_SPACEINSET_H
#include "InsetMath.h"
#include "Length.h"
namespace lyx {
@ -22,9 +23,13 @@ namespace lyx {
class InsetMathSpace : public InsetMath {
public:
///
explicit InsetMathSpace(int sp);
explicit InsetMathSpace();
///
explicit InsetMathSpace(docstring const & name);
explicit InsetMathSpace(std::string const & name, std::string const & length);
///
explicit InsetMathSpace(Length const & length);
///
~InsetMathSpace();
///
InsetMathSpace const * asSpaceInset() const { return this; }
///
@ -48,12 +53,25 @@ public:
void octave(OctaveStream &) const;
///
void write(WriteStream & os) const;
/// generate something that will be understood by the Dialogs.
std::string const createDialogStr() const;
///
EDITABLE editable() const { return IS_EDITABLE; }
///
docstring contextMenu(BufferView const &, int, int) const;
///
bool getStatus(Cursor &, FuncRequest const &, FuncStatus &) const;
protected:
///
virtual void doDispatch(Cursor & cur, FuncRequest & cmd);
private:
virtual Inset * clone() const;
///
int space_;
bool isNegative() const;
///
Dimension dim_;
int space_;
/// amount of space for \\hspace
Length length_;
};

View File

@ -52,6 +52,7 @@
#include "MathSupport.h"
#include "insets/InsetCommand.h"
#include "insets/InsetSpace.h"
#include "support/debug.h"
#include "support/docstream.h"
@ -61,7 +62,9 @@
#include "frontends/FontLoader.h"
#include "Encoding.h"
#include "LyX.h" // use_gui
#include "OutputParams.h"
using namespace std;
using namespace lyx::support;
@ -317,7 +320,7 @@ MathAtom createInsetMath(docstring const & s)
if (inset == "decoration")
return MathAtom(new InsetMathDecoration(l));
if (inset == "space")
return MathAtom(new InsetMathSpace(l->name));
return MathAtom(new InsetMathSpace(to_ascii(l->name), ""));
if (inset == "dots")
return MathAtom(new InsetMathDots(l));
if (inset == "mbox")
@ -477,13 +480,28 @@ bool createInsetMath_fromDialogStr(docstring const & str, MathData & ar)
docstring name;
docstring body = split(str, name, ' ');
if (name != "ref" )
if (name == "ref") {
InsetCommandParams icp(REF_CODE);
// FIXME UNICODE
InsetCommand::string2params("ref", to_utf8(str), icp);
mathed_parse_cell(ar, icp.getCommand());
} else if (name == "mathspace") {
InsetSpaceParams isp(true);
InsetSpace::string2params(to_utf8(str), isp);
InsetSpace is(isp);
odocstringstream os;
Encoding const * const ascii = encodings.fromLyXName("ascii");
OutputParams op(ascii);
is.latex(os, op);
mathed_parse_cell(ar, os.str());
if (ar.size() == 2) {
// remove "{}"
if (ar[1].nucleus()->asBraceInset())
ar.pop_back();
}
} else
return false;
InsetCommandParams icp(REF_CODE);
// FIXME UNICODE
InsetCommand::string2params("ref", to_utf8(str), icp);
mathed_parse_cell(ar, icp.getCommand());
if (ar.size() != 1)
return false;

View File

@ -54,6 +54,7 @@ following hack as starting point to write some macros:
#include "InsetMathRef.h"
#include "InsetMathRoot.h"
#include "InsetMathScript.h"
#include "InsetMathSpace.h"
#include "InsetMathSplit.h"
#include "InsetMathSqrt.h"
#include "InsetMathTabular.h"
@ -671,7 +672,7 @@ docstring Parser::parse_verbatim_option()
putback();
res += '{' + parse_verbatim_item() + '}';
} else
res += t.asString();
res += t.asInput();
}
}
return res;
@ -690,7 +691,7 @@ docstring Parser::parse_verbatim_item()
res += '{' + parse_verbatim_item() + '}';
}
else
res += t.asString();
res += t.asInput();
}
}
return res;
@ -1594,6 +1595,22 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
parse(cell->back().nucleus()->cell(0), FLAG_ITEM, InsetMath::TEXT_MODE);
}
else if (t.cs() == "hspace" && nextToken().character() != '*') {
docstring const name = t.cs();
docstring const arg = parse_verbatim_item();
Length length;
if (isValidLength(to_utf8(arg), &length))
cell->push_back(MathAtom(new InsetMathSpace(length)));
else {
// Since the Length class cannot use length variables
// we must not create an InsetMathSpace.
cell->push_back(MathAtom(new MathMacro(name)));
MathData ar;
mathed_parse_cell(ar, '{' + arg + '}');
cell->append(ar);
}
}
#if 0
else if (t.cs() == "infer") {
MathData ar;