]> git.lyx.org Git - lyx.git/blob - src/insets/InsetPhantom.cpp
Change cursor shape for clickable math insets
[lyx.git] / src / insets / InsetPhantom.cpp
1 /**
2  * \file InsetPhantom.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Uwe Stöhr
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "InsetPhantom.h"
14
15 #include "Buffer.h"
16 #include "BufferParams.h"
17 #include "BufferView.h"
18 #include "Cursor.h"
19 #include "Dimension.h"
20 #include "DispatchResult.h"
21 #include "Exporter.h"
22 #include "FuncRequest.h"
23 #include "FuncStatus.h"
24 #include "LaTeXFeatures.h"
25 #include "Lexer.h"
26 #include "MetricsInfo.h"
27 #include "texstream.h"
28 #include "TextClass.h"
29
30 #include "support/docstream.h"
31 #include "support/gettext.h"
32 #include "support/lstrings.h"
33 #include "support/Translator.h"
34
35 #include "frontends/Application.h"
36 #include "frontends/FontMetrics.h"
37 #include "frontends/Painter.h"
38
39 #include <algorithm>
40 #include <sstream>
41
42 using namespace std;
43
44 namespace lyx {
45
46 namespace {
47
48 typedef Translator<string, InsetPhantomParams::Type> PhantomTranslator;
49 typedef Translator<docstring, InsetPhantomParams::Type> PhantomTranslatorLoc;
50
51 PhantomTranslator const init_phantomtranslator()
52 {
53         PhantomTranslator translator("Phantom", InsetPhantomParams::Phantom);
54         translator.addPair("HPhantom", InsetPhantomParams::HPhantom);
55         translator.addPair("VPhantom", InsetPhantomParams::VPhantom);
56         return translator;
57 }
58
59
60 PhantomTranslatorLoc const init_phantomtranslator_loc()
61 {
62         PhantomTranslatorLoc translator(_("Phantom"), InsetPhantomParams::Phantom);
63         translator.addPair(_("HPhantom"), InsetPhantomParams::HPhantom);
64         translator.addPair(_("VPhantom"), InsetPhantomParams::VPhantom);
65         return translator;
66 }
67
68
69 PhantomTranslator const & phantomtranslator()
70 {
71         static PhantomTranslator const translator =
72             init_phantomtranslator();
73         return translator;
74 }
75
76
77 PhantomTranslatorLoc const & phantomtranslator_loc()
78 {
79         static PhantomTranslatorLoc const translator =
80             init_phantomtranslator_loc();
81         return translator;
82 }
83
84 } // namespace
85
86
87 InsetPhantomParams::InsetPhantomParams()
88         : type(Phantom)
89 {}
90
91
92 void InsetPhantomParams::write(ostream & os) const
93 {
94         string const label = phantomtranslator().find(type);
95         os << "Phantom " << label << "\n";
96 }
97
98
99 void InsetPhantomParams::read(Lexer & lex)
100 {
101         string label;
102         lex >> label;
103         if (lex)
104                 type = phantomtranslator().find(label);
105 }
106
107
108 /////////////////////////////////////////////////////////////////////
109 //
110 // InsetPhantom
111 //
112 /////////////////////////////////////////////////////////////////////
113
114 InsetPhantom::InsetPhantom(Buffer * buf, string const & label)
115         : InsetCollapsible(buf)
116 {
117         setDrawFrame(false);
118         params_.type = phantomtranslator().find(label);
119 }
120
121
122 InsetPhantom::~InsetPhantom()
123 {
124         hideDialogs("phantom", this);
125 }
126
127
128 docstring InsetPhantom::layoutName() const
129 {
130         return from_ascii("Phantom:" + phantomtranslator().find(params_.type));
131 }
132
133
134 void InsetPhantom::draw(PainterInfo & pi, int x, int y) const
135 {
136         // draw the text
137         InsetCollapsible::draw(pi, x, y);
138
139         // draw the inset marker
140         drawMarkers(pi, x, y);
141
142         // draw the arrow(s)
143         static int const arrow_size = 4;
144         ColorCode const origcol = pi.base.font.color();
145         pi.base.font.setColor(Color_special);
146         pi.base.font.setColor(origcol);
147         Dimension const dim = dimension(*pi.base.bv);
148
149         if (params_.type == InsetPhantomParams::Phantom ||
150                 params_.type == InsetPhantomParams::VPhantom) {
151                 // y1---------
152                 //           / \.
153                 // y2-----  / | \.
154                 //            |
155                 //            |
156                 // y3-----  \ | /
157                 //           \ /
158                 // y4---------
159                 //          | | |
160                 //         /  |  \.
161                 //        x1  x2 x3
162
163                 int const x2 = x + dim.wid / 2;
164                 int const x1 = x2 - arrow_size;
165                 int const x3 = x2 + arrow_size;
166
167                 int const y1 = y - dim.asc;
168                 int const y2 = y1 + arrow_size;
169                 int const y4 = y + dim.des;
170                 int const y3 = y4 - arrow_size;
171
172                 // top arrow
173                 pi.pain.line(x2, y1, x1, y2, Color_added_space);
174                 pi.pain.line(x2, y1, x3, y2, Color_added_space);
175
176                 // bottom arrow
177                 pi.pain.line(x2, y4, x1, y3, Color_added_space);
178                 pi.pain.line(x2, y4, x3, y3, Color_added_space);
179
180                 // joining line
181                 pi.pain.line(x2, y1, x2, y4, Color_added_space);
182         }
183
184         if (params_.type == InsetPhantomParams::Phantom ||
185                 params_.type == InsetPhantomParams::HPhantom) {
186                 // y1----   /          \.
187                 //        /              \.
188                 // y2--- <---------------->
189                 //        \              /
190                 // y3----   \          /
191                 //       |   |        |   |
192                 //      x1  x2       x3  x4
193
194                 x += leftOffset(pi.base.bv);
195                 int const x1 = x;
196                 int const x2 = x + arrow_size;
197                 int const x4 = x + dim.wid - leftOffset(pi.base.bv) - rightOffset(pi.base.bv);
198                 int const x3 = x4 - arrow_size;
199
200                 int const y2 = y + (dim.des - dim.asc) / 2;
201                 int const y1 = y2 - arrow_size;
202                 int const y3 = y2 + arrow_size;
203
204                 // left arrow
205                 pi.pain.line(x1, y2, x2, y3, Color_added_space);
206                 pi.pain.line(x1, y2, x2, y1, Color_added_space);
207
208                 // right arrow
209                 pi.pain.line(x4, y2, x3, y3, Color_added_space);
210                 pi.pain.line(x4, y2, x3, y1, Color_added_space);
211
212                 // joining line
213                 pi.pain.line(x1, y2, x4, y2, Color_added_space);
214         }
215 }
216
217
218 void InsetPhantom::write(ostream & os) const
219 {
220         params_.write(os);
221         InsetCollapsible::write(os);
222 }
223
224
225 void InsetPhantom::read(Lexer & lex)
226 {
227         params_.read(lex);
228         InsetCollapsible::read(lex);
229 }
230
231
232 void InsetPhantom::setButtonLabel()
233 {
234         docstring const label = phantomtranslator_loc().find(params_.type);
235         setLabel(label);
236 }
237
238
239 bool InsetPhantom::showInsetDialog(BufferView * bv) const
240 {
241         bv->showDialog("phantom", params2string(params()),
242                 const_cast<InsetPhantom *>(this));
243         return true;
244 }
245
246
247 void InsetPhantom::doDispatch(Cursor & cur, FuncRequest & cmd)
248 {
249         switch (cmd.action()) {
250
251         case LFUN_INSET_MODIFY:
252                 cur.recordUndoInset(this);
253                 string2params(to_utf8(cmd.argument()), params_);
254                 setButtonLabel();
255                 cur.forceBufferUpdate();
256                 break;
257
258         case LFUN_INSET_DIALOG_UPDATE:
259                 cur.bv().updateDialog("phantom", params2string(params()));
260                 break;
261
262         default:
263                 InsetCollapsible::doDispatch(cur, cmd);
264                 break;
265         }
266 }
267
268
269 bool InsetPhantom::getStatus(Cursor & cur, FuncRequest const & cmd,
270                 FuncStatus & flag) const
271 {
272         switch (cmd.action()) {
273
274         case LFUN_INSET_MODIFY:
275                 if (cmd.getArg(0) == "phantom") {
276                         InsetPhantomParams params;
277                         string2params(to_utf8(cmd.argument()), params);
278                         flag.setOnOff(params_.type == params.type);
279                 }
280                 flag.setEnabled(true);
281                 return true;
282
283         case LFUN_INSET_DIALOG_UPDATE:
284                 flag.setEnabled(true);
285                 return true;
286
287         default:
288                 return InsetCollapsible::getStatus(cur, cmd, flag);
289         }
290 }
291
292
293 docstring InsetPhantom::toolTip(BufferView const &, int, int) const
294 {
295         docstring const res = phantomtranslator_loc().find(params_.type);
296         return toolTipText(res + from_ascii(": "));
297 }
298
299
300 void InsetPhantom::latex(otexstream & os, OutputParams const & runparams) const
301 {
302         if (runparams.moving_arg)
303                 os << "\\protect";
304
305         switch (params_.type) {
306         case InsetPhantomParams::Phantom:
307                 os << "\\phantom{";
308                 break;
309         case InsetPhantomParams::HPhantom:
310                 os << "\\hphantom{";
311                 break;
312         case InsetPhantomParams::VPhantom:
313                 os << "\\vphantom{";
314                 break;
315         default:
316                 os << "\\phantom{";
317                 break;
318         }
319         InsetCollapsible::latex(os, runparams);
320         os << "}";
321 }
322
323
324 int InsetPhantom::plaintext(odocstringstream & os,
325                             OutputParams const & runparams, size_t max_length) const
326 {
327         switch (params_.type) {
328         case InsetPhantomParams::Phantom:
329                 os << '[' << buffer().B_("phantom") << ":";
330                 break;
331         case InsetPhantomParams::HPhantom:
332                 os << '[' << buffer().B_("hphantom") << ":";
333                 break;
334         case InsetPhantomParams::VPhantom:
335                 os << '[' << buffer().B_("vphantom") << ":";
336                 break;
337         default:
338                 os << '[' << buffer().B_("phantom") << ":";
339                 break;
340         }
341         InsetCollapsible::plaintext(os, runparams, max_length);
342         os << "]";
343
344         return PLAINTEXT_NEWLINE;
345 }
346
347
348 void InsetPhantom::docbook(XMLStream &, OutputParams const &) const
349 {
350         return;
351 }
352
353
354 docstring InsetPhantom::xhtml(XMLStream &, OutputParams const &) const
355 {
356         return docstring();
357 }
358
359 string InsetPhantom::contextMenuName() const
360 {
361         return "context-phantom";
362 }
363
364
365 string InsetPhantom::params2string(InsetPhantomParams const & params)
366 {
367         ostringstream data;
368         data << "phantom" << ' ';
369         params.write(data);
370         return data.str();
371 }
372
373
374 void InsetPhantom::string2params(string const & in, InsetPhantomParams & params)
375 {
376         params = InsetPhantomParams();
377
378         if (in.empty())
379                 return;
380
381         istringstream data(in);
382         Lexer lex;
383         lex.setStream(data);
384         lex.setContext("InsetPhantom::string2params");
385         lex >> "phantom" >> "Phantom";
386
387         params.read(lex);
388 }
389
390
391 } // namespace lyx