]> git.lyx.org Git - features.git/blob - src/mathed/InsetMathSpace.cpp
Introduce a return value for mathmlize(). We will need this to be able
[features.git] / src / mathed / InsetMathSpace.cpp
1 /**
2  * \file InsetMathSpace.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author André Pönitz
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "InsetMathSpace.h"
14 #include "MathData.h"
15 #include "MathFactory.h"
16 #include "MathStream.h"
17 #include "MathSupport.h"
18
19 #include "BufferView.h"
20 #include "Cursor.h"
21 #include "FuncRequest.h"
22 #include "FuncStatus.h"
23 #include "LaTeXFeatures.h"
24
25 #include "insets/InsetSpace.h"
26
27 #include "frontends/Application.h"
28 #include "frontends/Painter.h"
29
30 #include "support/lassert.h"
31
32 using namespace std;
33
34 namespace lyx {
35
36 namespace {
37
38 struct SpaceInfo {
39         string name;
40         int width;
41         InsetSpaceParams::Kind kind;
42         bool negative;
43         bool visible;
44         bool custom;
45 };
46
47 SpaceInfo space_info[] = {
48         // name           width kind                         negative visible custom
49         {"!",              6,   InsetSpaceParams::NEGTHIN,   true,    true,   false},
50         {"negthinspace",   6,   InsetSpaceParams::NEGTHIN,   true,    true,   false},
51         {"negmedspace",    8,   InsetSpaceParams::NEGMEDIUM, true,    true,   false},
52         {"negthickspace", 10,   InsetSpaceParams::NEGTHICK,  true,    true,   false},
53         {",",              6,   InsetSpaceParams::THIN,      false,   true,   false},
54         {"thinspace",      6,   InsetSpaceParams::THIN,      false,   true,   false},
55         {":",              8,   InsetSpaceParams::MEDIUM,    false,   true,   false},
56         {"medspace",       8,   InsetSpaceParams::MEDIUM,    false,   true,   false},
57         {";",             10,   InsetSpaceParams::THICK,     false,   true,   false},
58         {"thickspace",    10,   InsetSpaceParams::THICK,     false,   true,   false},
59         {"enskip",        10,   InsetSpaceParams::ENSKIP,    false,   true,   false},
60         {"quad",          20,   InsetSpaceParams::QUAD,      false,   true,   false},
61         {"qquad",         40,   InsetSpaceParams::QQUAD,     false,   true,   false},
62         {"lyxnegspace",   -2,   InsetSpaceParams::NEGTHIN,   true,    false,  false},
63         {"lyxposspace",    2,   InsetSpaceParams::THIN,      false,   false,  false},
64         {"hspace",         0,   InsetSpaceParams::CUSTOM,    false,   true,   true},
65 };
66
67 int const nSpace = sizeof(space_info)/sizeof(SpaceInfo);
68 int const defaultSpace = 4;
69
70 } // anon namespace
71
72 InsetMathSpace::InsetMathSpace()
73         : space_(defaultSpace)
74 {
75 }
76
77
78 InsetMathSpace::InsetMathSpace(string const & name, string const & length)
79         : space_(defaultSpace)
80 {
81         for (int i = 0; i < nSpace; ++i)
82                 if (space_info[i].name == name) {
83                         space_ = i;
84                         break;
85                 }
86         if (space_info[space_].custom) {
87                 length_ = Length(length);
88                 if (length_.zero() || length_.empty()) {
89                         length_.value(1.0);
90                         length_.unit(Length::EM);
91                 }
92         }
93 }
94
95
96 InsetMathSpace::InsetMathSpace(Length const & length)
97         : space_(defaultSpace), length_(length)
98 {
99         for (int i = 0; i < nSpace; ++i)
100                 if (space_info[i].name == "hspace") {
101                         space_ = i;
102                         break;
103                 }
104 }
105
106
107 InsetMathSpace::~InsetMathSpace()
108 {
109         hideDialogs("mathspace", this);
110 }
111
112
113 Inset * InsetMathSpace::clone() const
114 {
115         return new InsetMathSpace(*this);
116 }
117
118
119 void InsetMathSpace::metrics(MetricsInfo & mi, Dimension & dim) const
120 {
121         dim.asc = 4;
122         dim.des = 0;
123         if (space_info[space_].custom)
124                 dim.wid = abs(length_.inPixels(
125                                 mi.base.textwidth,
126                                 mathed_char_width(mi.base.font, 'M')));
127         else
128                 dim.wid = space_info[space_].width;
129 }
130
131
132 void InsetMathSpace::draw(PainterInfo & pi, int x, int y) const
133 {
134         // Sadly, HP-UX CC can't handle that kind of initialization.
135         // XPoint p[4] = {{++x, y-3}, {x, y}, {x+width-2, y}, {x+width-2, y-3}};
136         if (!space_info[space_].visible)
137                 return;
138
139         Dimension const dim = dimension(*pi.base.bv);
140         int xp[4];
141         int yp[4];
142         int w = dim.wid;
143
144         xp[0] = ++x;        yp[0] = y - 3;
145         xp[1] = x;          yp[1] = y;
146         xp[2] = x + w - 2;  yp[2] = y;
147         xp[3] = x + w - 2;  yp[3] = y - 3;
148
149         pi.pain.lines(xp, yp, 4,
150                         space_info[space_].custom ?
151                         Color_special :
152                         (isNegative() ? Color_latex : Color_math));
153 }
154
155
156 void InsetMathSpace::incSpace()
157 {
158         int const oldwidth = space_info[space_].width;
159         do
160                 space_ = (space_ + 1) % nSpace;
161         while ((space_info[space_].width == oldwidth && !space_info[space_].custom) ||
162                !space_info[space_].visible);
163         if (space_info[space_].custom && (length_.zero() || length_.empty())) {
164                 length_.value(1.0);
165                 length_.unit(Length::EM);
166         }
167 }
168
169
170 void InsetMathSpace::validate(LaTeXFeatures & features) const
171 {
172         if (space_info[space_].name == "negmedspace" ||
173             space_info[space_].name == "negthickspace")
174                 features.require("amsmath");
175 }
176
177
178 void InsetMathSpace::maple(MapleStream & os) const
179 {
180         os << ' ';
181 }
182
183 void InsetMathSpace::mathematica(MathematicaStream & os) const
184 {
185         os << ' ';
186 }
187
188
189 void InsetMathSpace::octave(OctaveStream & os) const
190 {
191         os << ' ';
192 }
193
194
195 docstring InsetMathSpace::mathmlize(MathStream & ms) const
196 {
197         SpaceInfo const & si = space_info[space_];
198         if (si.negative || !si.visible)
199                 return docstring();
200         string l;
201         if (si.custom)
202                 l = length_.asHTMLString();
203         else if (si.kind != InsetSpaceParams::MEDIUM) {
204                 stringstream ss;
205                 ss << si.width;
206                 l = ss.str() + "px";
207         }
208         
209         ms << "<mspace";
210         if (!l.empty())
211                 ms << " width=\"" << from_ascii(l) << "\"";
212         ms << " />";
213         return docstring();
214 }
215
216         
217 void InsetMathSpace::normalize(NormalStream & os) const
218 {
219         os << "[space " << int(space_) << "] ";
220 }
221
222
223 void InsetMathSpace::write(WriteStream & os) const
224 {
225         // no MathEnsurer - all kinds work in text and math mode
226         os << '\\' << space_info[space_].name.c_str();
227         if (space_info[space_].custom)
228                 os << '{' << length_.asLatexString().c_str() << '}';
229         else
230                 os.pendingSpace(true);
231 }
232
233
234 string const InsetMathSpace::createDialogStr() const
235 {
236         LASSERT(space_info[space_].visible, /**/);
237         InsetSpaceParams isp(true);
238         isp.kind = space_info[space_].kind;
239         isp.length = GlueLength(length_);
240         return InsetSpace::params2string(isp);
241 }
242
243
244 docstring InsetMathSpace::contextMenu(BufferView const &, int, int) const
245 {
246         return from_ascii("context-mathspace");
247 }
248
249
250 bool InsetMathSpace::getStatus(Cursor & cur, FuncRequest const & cmd,
251                                FuncStatus & status) const
252 {
253         switch (cmd.action) {
254         // we handle these
255         case LFUN_INSET_MODIFY:
256         case LFUN_INSET_DIALOG_UPDATE:
257         case LFUN_MOUSE_RELEASE:
258         case LFUN_MOUSE_PRESS:
259         case LFUN_MOUSE_MOTION:
260                 status.setEnabled(true);
261                 return true;
262         default:
263                 bool retval = InsetMath::getStatus(cur, cmd, status);
264                 return retval;
265         }
266 }
267
268
269 void InsetMathSpace::doDispatch(Cursor & cur, FuncRequest & cmd)
270 {
271         switch (cmd.action) {
272         case LFUN_INSET_MODIFY:
273                 if (cmd.getArg(0) == "mathspace") {
274                         MathData ar;
275                         if (createInsetMath_fromDialogStr(cmd.argument(), ar)) {
276                                 *this = *ar[0].nucleus()->asSpaceInset();
277                                 break;
278                         }
279                 }
280                 cur.undispatched();
281                 break;
282
283         case LFUN_INSET_DIALOG_UPDATE:
284                 cur.bv().updateDialog("mathspace", createDialogStr());
285                 break;
286
287         case LFUN_MOUSE_RELEASE:
288                 if (cmd.button() == mouse_button::button1) {
289                         string const data = createDialogStr();
290                         cur.bv().showDialog("mathspace", data, this);
291                         break;
292                 }
293                 cur.undispatched();
294                 break;
295
296         case LFUN_MOUSE_PRESS:
297         case LFUN_MOUSE_MOTION:
298                 // eat other mouse commands
299                 break;
300
301         default:
302                 InsetMath::doDispatch(cur, cmd);
303                 break;
304         }
305 }
306
307
308 bool InsetMathSpace::isNegative() const
309 {
310         if (space_info[space_].custom)
311                 return length_.value() < 0;
312         return space_info[space_].negative;
313 }
314
315 } // namespace lyx