]> git.lyx.org Git - lyx.git/blob - src/mathed/InsetMathSpace.cpp
Fix bug #6315: counters in insets that don't produce output have ghost values.
[lyx.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 Inset * InsetMathSpace::clone() const
108 {
109         return new InsetMathSpace(*this);
110 }
111
112
113 void InsetMathSpace::metrics(MetricsInfo & mi, Dimension & dim) const
114 {
115         dim.asc = 4;
116         dim.des = 0;
117         if (space_info[space_].custom)
118                 dim.wid = abs(length_.inPixels(
119                                 mi.base.textwidth,
120                                 mathed_char_width(mi.base.font, 'M')));
121         else
122                 dim.wid = space_info[space_].width;
123 }
124
125
126 void InsetMathSpace::draw(PainterInfo & pi, int x, int y) const
127 {
128         // Sadly, HP-UX CC can't handle that kind of initialization.
129         // XPoint p[4] = {{++x, y-3}, {x, y}, {x+width-2, y}, {x+width-2, y-3}};
130         if (!space_info[space_].visible)
131                 return;
132
133         Dimension const dim = dimension(*pi.base.bv);
134         int xp[4];
135         int yp[4];
136         int w = dim.wid;
137
138         xp[0] = ++x;        yp[0] = y - 3;
139         xp[1] = x;          yp[1] = y;
140         xp[2] = x + w - 2;  yp[2] = y;
141         xp[3] = x + w - 2;  yp[3] = y - 3;
142
143         pi.pain.lines(xp, yp, 4,
144                         space_info[space_].custom ?
145                         Color_special :
146                         (isNegative() ? Color_latex : Color_math));
147 }
148
149
150 void InsetMathSpace::incSpace()
151 {
152         int const oldwidth = space_info[space_].width;
153         do
154                 space_ = (space_ + 1) % nSpace;
155         while ((space_info[space_].width == oldwidth && !space_info[space_].custom) ||
156                !space_info[space_].visible);
157         if (space_info[space_].custom && (length_.zero() || length_.empty())) {
158                 length_.value(1.0);
159                 length_.unit(Length::EM);
160         }
161 }
162
163
164 void InsetMathSpace::validate(LaTeXFeatures & features) const
165 {
166         if (space_info[space_].name == "negmedspace" ||
167             space_info[space_].name == "negthickspace")
168                 features.require("amsmath");
169 }
170
171
172 void InsetMathSpace::maple(MapleStream & os) const
173 {
174         os << ' ';
175 }
176
177 void InsetMathSpace::mathematica(MathematicaStream & os) const
178 {
179         os << ' ';
180 }
181
182
183 void InsetMathSpace::octave(OctaveStream & os) const
184 {
185         os << ' ';
186 }
187
188
189 void InsetMathSpace::mathmlize(MathStream & ms) const
190 {
191         SpaceInfo const & si = space_info[space_];
192         if (si.negative || !si.visible)
193                 return;
194         string l;
195         if (si.custom)
196                 l = length_.asHTMLString();
197         else if (si.kind != InsetSpaceParams::MEDIUM) {
198                 stringstream ss;
199                 ss << si.width;
200                 l = ss.str() + "px";
201         }
202         
203         ms << "<mspace";
204         if (!l.empty())
205                 ms << " width=\"" << from_ascii(l) << "\"";
206         ms << " />";
207 }
208
209         
210 void InsetMathSpace::htmlize(HtmlStream & ms) const
211 {
212         SpaceInfo const & si = space_info[space_];
213         switch (si.kind) {
214         case InsetSpaceParams::THIN:
215                 ms << from_ascii("&thinsp;");
216                 break;
217         case InsetSpaceParams::MEDIUM:
218                 ms << from_ascii("&nbsp;");
219                 break;
220         case InsetSpaceParams::THICK:
221                 ms << from_ascii("&emsp;");
222                 break;
223         case InsetSpaceParams::ENSKIP:
224                 ms << from_ascii("&ensp;");
225                 break;
226         case InsetSpaceParams::QUAD:
227                 ms << from_ascii("&emsp;");
228                 break;
229         case InsetSpaceParams::QQUAD:
230                 ms << from_ascii("&emsp;&emsp;");
231                 break;
232         case InsetSpaceParams::CUSTOM: {
233                 string l = length_.asHTMLString();
234                 ms << MTag("span", "width='" + l + "'") 
235                    << from_ascii("&nbsp;") << ETag("span");
236                 break;
237         }
238         default:
239                 break;
240         }
241 }
242
243         
244 void InsetMathSpace::normalize(NormalStream & os) const
245 {
246         os << "[space " << int(space_) << "] ";
247 }
248
249
250 void InsetMathSpace::write(WriteStream & os) const
251 {
252         // no MathEnsurer - all kinds work in text and math mode
253         os << '\\' << space_info[space_].name.c_str();
254         if (space_info[space_].custom)
255                 os << '{' << length_.asLatexString().c_str() << '}';
256         else
257                 os.pendingSpace(true);
258 }
259
260
261 InsetSpaceParams InsetMathSpace::params() const
262 {
263         LASSERT(space_info[space_].visible, /**/);
264         InsetSpaceParams isp(true);
265         isp.kind = space_info[space_].kind;
266         isp.length = GlueLength(length_);
267         return isp;
268 }
269
270
271 docstring InsetMathSpace::contextMenu(BufferView const &, int, int) const
272 {
273         return from_ascii("context-mathspace");
274 }
275
276
277 bool InsetMathSpace::getStatus(Cursor & cur, FuncRequest const & cmd,
278                                FuncStatus & status) const
279 {
280         switch (cmd.action()) {
281         // we handle these
282         case LFUN_INSET_MODIFY:
283         case LFUN_INSET_DIALOG_UPDATE:
284         case LFUN_MOUSE_RELEASE:
285         case LFUN_MOUSE_PRESS:
286         case LFUN_MOUSE_MOTION:
287                 status.setEnabled(true);
288                 return true;
289         default:
290                 bool retval = InsetMath::getStatus(cur, cmd, status);
291                 return retval;
292         }
293 }
294
295
296 void InsetMathSpace::doDispatch(Cursor & cur, FuncRequest & cmd)
297 {
298         switch (cmd.action()) {
299         case LFUN_INSET_MODIFY:
300                 if (cmd.getArg(0) == "mathspace") {
301                         MathData ar;
302                         if (createInsetMath_fromDialogStr(cmd.argument(), ar)) {
303                                 cur.recordUndo();
304                                 *this = *ar[0].nucleus()->asSpaceInset();
305                                 break;
306                         }
307                 }
308                 cur.undispatched();
309                 break;
310
311         case LFUN_MOUSE_RELEASE:
312                 if (cmd.button() == mouse_button::button1) {
313                         showInsetDialog(&cur.bv());
314                         break;
315                 }
316                 cur.undispatched();
317                 break;
318
319         case LFUN_MOUSE_PRESS:
320         case LFUN_MOUSE_MOTION:
321                 // eat other mouse commands
322                 break;
323
324         default:
325                 InsetMath::doDispatch(cur, cmd);
326                 break;
327         }
328 }
329
330
331 bool InsetMathSpace::isNegative() const
332 {
333         if (space_info[space_].custom)
334                 return length_.value() < 0;
335         return space_info[space_].negative;
336 }
337
338 } // namespace lyx