2 * \file InsetMathSpace.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS.
13 #include "InsetMathSpace.h"
15 #include "MathFactory.h"
16 #include "MathStream.h"
17 #include "MathSupport.h"
19 #include "BufferView.h"
21 #include "FuncRequest.h"
22 #include "FuncStatus.h"
23 #include "LaTeXFeatures.h"
24 #include "MetricsInfo.h"
26 #include "insets/InsetSpace.h"
28 #include "frontends/Application.h"
29 #include "frontends/Painter.h"
31 #include "support/lassert.h"
42 InsetSpaceParams::Kind kind;
46 bool escape; ///< whether a backslash needs to be added for writing
49 SpaceInfo space_info[] = {
50 // name width kind negative visible custom escape
51 {"!", 6, InsetSpaceParams::NEGTHIN, true, true, false, true},
52 {"negthinspace", 6, InsetSpaceParams::NEGTHIN, true, true, false, true},
53 {"negmedspace", 8, InsetSpaceParams::NEGMEDIUM, true, true, false, true},
54 {"negthickspace", 10, InsetSpaceParams::NEGTHICK, true, true, false, true},
55 {",", 6, InsetSpaceParams::THIN, false, true, false, true},
56 {"thinspace", 6, InsetSpaceParams::THIN, false, true, false, true},
57 {":", 8, InsetSpaceParams::MEDIUM, false, true, false, true},
58 {"medspace", 8, InsetSpaceParams::MEDIUM, false, true, false, true},
59 {";", 10, InsetSpaceParams::THICK, false, true, false, true},
60 {"thickspace", 10, InsetSpaceParams::THICK, false, true, false, true},
61 {"enskip", 10, InsetSpaceParams::ENSKIP, false, true, false, true},
62 {"enspace", 10, InsetSpaceParams::ENSPACE, false, true, false, true},
63 {"quad", 20, InsetSpaceParams::QUAD, false, true, false, true},
64 {"qquad", 40, InsetSpaceParams::QQUAD, false, true, false, true},
65 {"lyxnegspace", -2, InsetSpaceParams::NEGTHIN, true, false, false, true},
66 {"lyxposspace", 2, InsetSpaceParams::THIN, false, false, false, true},
67 {"hfill", 80, InsetSpaceParams::HFILL, false, true, false, true},
68 {"hspace*{\\fill}", 80, InsetSpaceParams::HFILL_PROTECTED, false, true, false, true},
69 {"hspace*", 0, InsetSpaceParams::CUSTOM_PROTECTED,false, true, true, true},
70 {"hspace", 0, InsetSpaceParams::CUSTOM, false, true, true, true},
71 {" ", 10, InsetSpaceParams::NORMAL, false, true, false, true},
72 {"~", 10, InsetSpaceParams::PROTECTED, false, true, false, false},
75 int const nSpace = sizeof(space_info)/sizeof(SpaceInfo);
76 int const defaultSpace = 4;
80 InsetMathSpace::InsetMathSpace()
81 : space_(defaultSpace)
86 InsetMathSpace::InsetMathSpace(string const & name, string const & length)
87 : space_(defaultSpace)
89 for (int i = 0; i < nSpace; ++i)
90 if (space_info[i].name == name) {
94 if (space_info[space_].custom) {
95 length_ = Length(length);
96 if (length_.zero() || length_.empty()) {
98 length_.unit(Length::EM);
104 InsetMathSpace::InsetMathSpace(Length const & length, bool const prot)
105 : space_(defaultSpace), length_(length)
107 for (int i = 0; i < nSpace; ++i)
108 if ((prot && space_info[i].name == "hspace*")
109 || (!prot && space_info[i].name == "hspace")) {
116 Inset * InsetMathSpace::clone() const
118 return new InsetMathSpace(*this);
122 void InsetMathSpace::metrics(MetricsInfo & mi, Dimension & dim) const
124 Changer dummy = mi.base.changeEnsureMath();
127 if (space_info[space_].custom)
128 dim.wid = abs(mi.base.inPixels(length_));
130 dim.wid = space_info[space_].width;
134 void InsetMathSpace::draw(PainterInfo & pi, int x, int y) const
136 Changer dummy = pi.base.changeEnsureMath();
137 // Sadly, HP-UX CC can't handle that kind of initialization.
138 // XPoint p[4] = {{++x, y-3}, {x, y}, {x+width-2, y}, {x+width-2, y-3}};
139 if (!space_info[space_].visible)
142 Dimension const dim = dimension(*pi.base.bv);
147 xp[0] = ++x; yp[0] = y - 3;
148 xp[1] = x; yp[1] = y;
149 xp[2] = x + w - 2; yp[2] = y;
150 xp[3] = x + w - 2; yp[3] = y - 3;
152 pi.pain.lines(xp, yp, 4,
153 space_info[space_].custom ?
155 (isNegative() ? Color_latex : Color_math));
159 void InsetMathSpace::incSpace()
161 int const oldwidth = space_info[space_].width;
163 space_ = (space_ + 1) % nSpace;
164 while ((space_info[space_].width == oldwidth && !space_info[space_].custom) ||
165 !space_info[space_].visible);
166 if (space_info[space_].custom && (length_.zero() || length_.empty())) {
168 length_.unit(Length::EM);
173 void InsetMathSpace::validate(LaTeXFeatures & features) const
175 if (space_info[space_].name == "negmedspace" ||
176 space_info[space_].name == "negthickspace")
177 features.require("amsmath");
181 void InsetMathSpace::maple(MapleStream & os) const
186 void InsetMathSpace::mathematica(MathematicaStream & os) const
192 void InsetMathSpace::octave(OctaveStream & os) const
198 void InsetMathSpace::mathmlize(MathMLStream & ms) const
200 SpaceInfo const & si = space_info[space_];
201 if (si.negative || !si.visible)
205 l = length_.asHTMLString();
206 else if (si.kind != InsetSpaceParams::MEDIUM) {
212 ms << "<" << from_ascii(ms.namespacedTag("mspace"));
214 ms << " width=\"" << from_ascii(l) << "\"";
219 void InsetMathSpace::htmlize(HtmlStream & ms) const
221 SpaceInfo const & si = space_info[space_];
223 case InsetSpaceParams::THIN:
224 ms << from_ascii(" ");
226 case InsetSpaceParams::MEDIUM:
227 ms << from_ascii(" ");
229 case InsetSpaceParams::THICK:
230 ms << from_ascii(" ");
232 case InsetSpaceParams::ENSKIP:
233 case InsetSpaceParams::ENSPACE:
234 ms << from_ascii(" ");
236 case InsetSpaceParams::QUAD:
237 ms << from_ascii(" ");
239 case InsetSpaceParams::QQUAD:
240 ms << from_ascii("  ");
242 case InsetSpaceParams::HFILL:
243 case InsetSpaceParams::HFILL_PROTECTED:
244 // FIXME: is there a useful HTML entity?
246 case InsetSpaceParams::CUSTOM:
247 case InsetSpaceParams::CUSTOM_PROTECTED: {
248 string l = length_.asHTMLString();
249 ms << MTag("span", "width='" + l + "'")
250 << from_ascii(" ") << ETag("span");
253 case InsetSpaceParams::NORMAL:
254 case InsetSpaceParams::PROTECTED:
255 ms << from_ascii(" ");
263 void InsetMathSpace::normalize(NormalStream & os) const
265 os << "[space " << int(space_) << "] ";
269 void InsetMathSpace::write(TeXMathStream & os) const
271 // All kinds work in text and math mode, so simply suspend
272 // writing a possibly pending mode closing brace.
273 MathEnsurer ensurer(os, false);
274 if (space_info[space_].escape)
276 os << space_info[space_].name.c_str();
277 if (space_info[space_].custom)
278 os << '{' << length_.asLatexString().c_str() << '}';
279 else if (space_info[space_].escape && space_info[space_].name.length() > 1)
280 os.pendingSpace(true);
284 InsetSpaceParams InsetMathSpace::params() const
286 InsetSpaceParams isp(true);
287 LASSERT(space_info[space_].visible, return isp);
288 isp.kind = space_info[space_].kind;
289 isp.length = GlueLength(length_);
294 string InsetMathSpace::contextMenuName() const
296 return "context-mathspace";
300 bool InsetMathSpace::getStatus(Cursor & cur, FuncRequest const & cmd,
301 FuncStatus & status) const
303 switch (cmd.action()) {
305 case LFUN_INSET_MODIFY:
306 case LFUN_INSET_DIALOG_UPDATE:
307 case LFUN_MOUSE_RELEASE:
308 status.setEnabled(true);
311 bool retval = InsetMath::getStatus(cur, cmd, status);
317 void InsetMathSpace::doDispatch(Cursor & cur, FuncRequest & cmd)
319 switch (cmd.action()) {
320 case LFUN_INSET_MODIFY:
321 if (cmd.getArg(0) == "mathspace") {
323 if (createInsetMath_fromDialogStr(cmd.argument(), ar)) {
324 Buffer * buf = buffer_;
326 *this = *ar[0].nucleus()->asSpaceInset();
334 case LFUN_MOUSE_RELEASE:
335 if (cmd.button() == mouse_button::button1 && !cur.selection()) {
336 showInsetDialog(&cur.bv());
343 InsetMath::doDispatch(cur, cmd);
349 bool InsetMathSpace::isNegative() const
351 if (space_info[space_].custom)
352 return length_.value() < 0;
353 return space_info[space_].negative;