]> git.lyx.org Git - lyx.git/blob - src/mathed/InsetMathSpace.cpp
c771d2595bcd402c2d7521354353bde781cf1943
[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 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 void InsetMathSpace::mathmlize(MathStream & ms) const
196 {
197         SpaceInfo const & si = space_info[space_];
198         if (si.negative || !si.visible)
199                 return;
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 }
214
215         
216 void InsetMathSpace::normalize(NormalStream & os) const
217 {
218         os << "[space " << int(space_) << "] ";
219 }
220
221
222 void InsetMathSpace::write(WriteStream & os) const
223 {
224         // no MathEnsurer - all kinds work in text and math mode
225         os << '\\' << space_info[space_].name.c_str();
226         if (space_info[space_].custom)
227                 os << '{' << length_.asLatexString().c_str() << '}';
228         else
229                 os.pendingSpace(true);
230 }
231
232
233 string const InsetMathSpace::createDialogStr() const
234 {
235         LASSERT(space_info[space_].visible, /**/);
236         InsetSpaceParams isp(true);
237         isp.kind = space_info[space_].kind;
238         isp.length = GlueLength(length_);
239         return InsetSpace::params2string(isp);
240 }
241
242
243 docstring InsetMathSpace::contextMenu(BufferView const &, int, int) const
244 {
245         return from_ascii("context-mathspace");
246 }
247
248
249 bool InsetMathSpace::getStatus(Cursor & cur, FuncRequest const & cmd,
250                                FuncStatus & status) const
251 {
252         switch (cmd.action) {
253         // we handle these
254         case LFUN_INSET_MODIFY:
255         case LFUN_INSET_DIALOG_UPDATE:
256         case LFUN_MOUSE_RELEASE:
257         case LFUN_MOUSE_PRESS:
258         case LFUN_MOUSE_MOTION:
259                 status.setEnabled(true);
260                 return true;
261         default:
262                 bool retval = InsetMath::getStatus(cur, cmd, status);
263                 return retval;
264         }
265 }
266
267
268 void InsetMathSpace::doDispatch(Cursor & cur, FuncRequest & cmd)
269 {
270         switch (cmd.action) {
271         case LFUN_INSET_MODIFY:
272                 if (cmd.getArg(0) == "mathspace") {
273                         MathData ar;
274                         if (createInsetMath_fromDialogStr(cmd.argument(), ar)) {
275                                 *this = *ar[0].nucleus()->asSpaceInset();
276                                 break;
277                         }
278                 }
279                 cur.undispatched();
280                 break;
281
282         case LFUN_INSET_DIALOG_UPDATE:
283                 cur.bv().updateDialog("mathspace", createDialogStr());
284                 break;
285
286         case LFUN_MOUSE_RELEASE:
287                 if (cmd.button() == mouse_button::button1) {
288                         string const data = createDialogStr();
289                         cur.bv().showDialog("mathspace", data, this);
290                         break;
291                 }
292                 cur.undispatched();
293                 break;
294
295         case LFUN_MOUSE_PRESS:
296         case LFUN_MOUSE_MOTION:
297                 // eat other mouse commands
298                 break;
299
300         default:
301                 InsetMath::doDispatch(cur, cmd);
302                 break;
303         }
304 }
305
306
307 bool InsetMathSpace::isNegative() const
308 {
309         if (space_info[space_].custom)
310                 return length_.value() < 0;
311         return space_info[space_].negative;
312 }
313
314 } // namespace lyx