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