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