diff --git a/lib/symbols b/lib/symbols index 66b8be98be..e32f50dfc9 100644 --- a/lib/symbols +++ b/lib/symbols @@ -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 diff --git a/lib/ui/stdcontext.inc b/lib/ui/stdcontext.inc index 3559143a42..102a059863 100644 --- a/lib/ui/stdcontext.inc +++ b/lib/ui/stdcontext.inc @@ -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 # diff --git a/src/factory.cpp b/src/factory.cpp index 01e8c72652..0caddc872e 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -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*") diff --git a/src/frontends/qt4/GuiHSpace.cpp b/src/frontends/qt4/GuiHSpace.cpp index 984cd1a1e0..1967c2431d 100644 --- a/src/frontends/qt4/GuiHSpace.cpp +++ b/src/frontends/qt4/GuiHSpace.cpp @@ -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 diff --git a/src/frontends/qt4/GuiHSpace.h b/src/frontends/qt4/GuiHSpace.h index 582afc932b..5b0bdece3b 100644 --- a/src/frontends/qt4/GuiHSpace.h +++ b/src/frontends/qt4/GuiHSpace.h @@ -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 diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index db1289fe1d..483f7a0f53 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -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") diff --git a/src/frontends/qt4/ui/HSpaceUi.ui b/src/frontends/qt4/ui/HSpaceUi.ui index 613dfa20e9..5d6a7b5b8f 100644 --- a/src/frontends/qt4/ui/HSpaceUi.ui +++ b/src/frontends/qt4/ui/HSpaceUi.ui @@ -79,46 +79,6 @@ Supported spacing types - - - Inter-word space - - - - - Thin space - - - - - Negative thin space - - - - - Half Quad (0.5 em) - - - - - Quad (1 em) - - - - - Double Quad (2 em) - - - - - Horizontal Fill - - - - - Custom - - diff --git a/src/insets/InsetSpace.cpp b/src/insets/InsetSpace.cpp index d5c6619c19..c4827d28ce 100644 --- a/src/insets/InsetSpace.cpp +++ b/src/insets/InsetSpace.cpp @@ -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 << " "; 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(); diff --git a/src/insets/InsetSpace.h b/src/insets/InsetSpace.h index 8363645698..777456a7d9 100644 --- a/src/insets/InsetSpace.h +++ b/src/insets/InsetSpace.h @@ -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_; }; diff --git a/src/mathed/InsetMathNest.cpp b/src/mathed/InsetMathNest.cpp index ef2d659d8d..11531f6614 100644 --- a/src/mathed/InsetMathNest.cpp +++ b/src/mathed/InsetMathNest.cpp @@ -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; } diff --git a/src/mathed/InsetMathSpace.cpp b/src/mathed/InsetMathSpace.cpp index 6a0aae0ede..f3c05358cf 100644 --- a/src/mathed/InsetMathSpace.cpp +++ b/src/mathed/InsetMathSpace.cpp @@ -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 diff --git a/src/mathed/InsetMathSpace.h b/src/mathed/InsetMathSpace.h index eb89e8c50c..15b79d2b58 100644 --- a/src/mathed/InsetMathSpace.h +++ b/src/mathed/InsetMathSpace.h @@ -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_; }; diff --git a/src/mathed/MathFactory.cpp b/src/mathed/MathFactory.cpp index d12ac0aa56..943c7e8ff6 100644 --- a/src/mathed/MathFactory.cpp +++ b/src/mathed/MathFactory.cpp @@ -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; diff --git a/src/mathed/MathParser.cpp b/src/mathed/MathParser.cpp index 3cb58f42b7..3845bbc8a3 100644 --- a/src/mathed/MathParser.cpp +++ b/src/mathed/MathParser.cpp @@ -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;