]> git.lyx.org Git - lyx.git/blob - src/insets/InsetScript.cpp
Rename InsetXXX::contextMenu to InsetXXX::contextMenuName. Now this function doesn...
[lyx.git] / src / insets / InsetScript.cpp
1 /**
2  * \file InsetScript.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Georg Baum
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "InsetScript.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 "LyXAction.h"
27 #include "MetricsInfo.h"
28 #include "OutputParams.h"
29 #include "output_xhtml.h"
30 #include "TextClass.h"
31 #include "TextMetrics.h"
32
33 #include "support/docstream.h"
34 #include "support/gettext.h"
35 #include "support/lstrings.h"
36 #include "support/Translator.h"
37
38 #include "frontends/Application.h"
39 #include "frontends/FontMetrics.h"
40 #include "frontends/Painter.h"
41
42 #include <algorithm>
43
44 using namespace std;
45
46 namespace lyx {
47
48 namespace {
49
50 typedef Translator<string, InsetScriptParams::Type> ScriptTranslator;
51 typedef Translator<docstring, InsetScriptParams::Type> ScriptTranslatorLoc;
52
53 ScriptTranslator const init_scripttranslator()
54 {
55         ScriptTranslator translator("subscript", InsetScriptParams::Subscript);
56         translator.addPair("superscript", InsetScriptParams::Superscript);
57         return translator;
58 }
59
60
61 ScriptTranslatorLoc const init_scripttranslator_loc()
62 {
63         ScriptTranslatorLoc translator(_("Subscript"), InsetScriptParams::Subscript);
64         translator.addPair(_("Superscript"), InsetScriptParams::Superscript);
65         return translator;
66 }
67
68
69 ScriptTranslator const & scripttranslator()
70 {
71         static ScriptTranslator translator = init_scripttranslator();
72         return translator;
73 }
74
75
76 ScriptTranslatorLoc const & scripttranslator_loc()
77 {
78         static ScriptTranslatorLoc translator = init_scripttranslator_loc();
79         return translator;
80 }
81
82 } // anon
83
84
85 InsetScriptParams::InsetScriptParams()
86         : type(Subscript)
87 {}
88
89
90 void InsetScriptParams::write(ostream & os) const
91 {
92         string const label = scripttranslator().find(type);
93         os << "script " << label << "\n";
94 }
95
96
97 void InsetScriptParams::read(Lexer & lex)
98 {
99         string label;
100         lex >> label;
101         if (lex)
102                 type = scripttranslator().find(label);
103 }
104
105
106 int InsetScriptParams::shift(FontInfo const & font) const
107 {
108         frontend::FontMetrics const & fm = theFontMetrics(font);
109         switch (type) {
110         case Subscript:
111                 return fm.maxAscent() / 3;
112         case Superscript:
113                 return -fm.maxAscent() / 2;
114         }
115         // shut up compiler
116         return 0;
117 }
118
119
120 /////////////////////////////////////////////////////////////////////
121 //
122 // InsetScript
123 //
124 /////////////////////////////////////////////////////////////////////
125
126 InsetScript::InsetScript(Buffer * buf, InsetScriptParams const & params)
127         : InsetText(buf, InsetText::PlainLayout), params_(params)
128 {
129         setDrawFrame(false);
130 }
131
132
133 InsetScript::InsetScript(Buffer * buf, string const & label)
134         : InsetText(buf)
135 {
136         setDrawFrame(false);
137         params_.type = scripttranslator().find(label);
138 }
139
140
141 InsetScript::~InsetScript()
142 {
143 }
144
145
146 docstring InsetScript::name() const 
147 {
148         return from_ascii("script:" + scripttranslator().find(params_.type));
149 }
150
151
152 Inset::DisplayType InsetScript::display() const
153 {
154         return Inline;
155 }
156
157
158 void InsetScript::metrics(MetricsInfo & mi, Dimension & dim) const
159 {
160         int const shift = params_.shift(mi.base.font);
161         ScriptChanger dummy(mi.base);
162         InsetText::metrics(mi, dim);
163         dim.asc -= shift;
164         dim.des += shift;
165 }
166
167
168 void InsetScript::draw(PainterInfo & pi, int x, int y) const
169 {
170         int const shift = params_.shift(pi.base.font);
171         ScriptChanger dummy(pi.base);
172         InsetText::draw(pi, x, y + shift);
173 }
174
175
176 void InsetScript::cursorPos(BufferView const & bv,
177                 CursorSlice const & sl, bool boundary, int & x, int & y) const
178 {
179         Font const font = bv.textMetrics(&text()).displayFont(sl.pit(), sl.pos());
180         int const shift = params_.shift(font.fontInfo());
181         InsetText::cursorPos(bv, sl, boundary, x, y);
182         y += shift;
183 }
184
185
186 void InsetScript::write(ostream & os) const
187 {
188         params_.write(os);
189         text().write(os);
190 }
191
192
193 void InsetScript::read(Lexer & lex)
194 {
195         params_.read(lex);
196         InsetText::read(lex);
197 }
198
199
200 void InsetScript::edit(Cursor & cur, bool front, EntryDirection entry_from)
201 {
202         cur.push(*this);
203         InsetText::edit(cur, front, entry_from);
204 }
205
206
207 Inset * InsetScript::editXY(Cursor & cur, int x, int y)
208 {
209         cur.push(*this);
210         return InsetText::editXY(cur, x, y);
211 }
212
213 void InsetScript::doDispatch(Cursor & cur, FuncRequest & cmd)
214 {
215         switch (cmd.action()) {
216         case LFUN_INSET_MODIFY:
217                 cur.recordUndoInset(ATOMIC_UNDO, this);
218                 string2params(to_utf8(cmd.argument()), params_);
219                 break;
220         default:
221                 InsetText::doDispatch(cur, cmd);
222                 break;
223         }
224 }
225
226
227 bool InsetScript::insetAllowed(InsetCode code) const
228 {
229         switch (code) {
230         // code that is not allowed in a script
231         case BIBITEM_CODE:
232         case BIBTEX_CODE:
233         case BOX_CODE:
234         case BRANCH_CODE:
235         case CAPTION_CODE:
236         case COLLAPSABLE_CODE:
237         case FLOAT_CODE:
238         case FLOAT_LIST_CODE:
239         case FOOT_CODE:
240         case INCLUDE_CODE:
241         case INDEX_PRINT_CODE:
242         case LISTINGS_CODE:
243         case MARGIN_CODE:
244         case MATH_MACRO_CODE:
245         case MATHMACRO_CODE:
246         case NEWLINE_CODE:
247         case NEWPAGE_CODE:
248         case NOMENCL_PRINT_CODE:
249         case QUOTE_CODE:
250         case PREVIEW_CODE:
251         case TABULAR_CODE:
252         case TOC_CODE:
253         case WRAP_CODE:
254                 return false;
255         default:
256                 return InsetText::insetAllowed(code);
257         }
258 }
259
260 bool InsetScript::getStatus(Cursor & cur, FuncRequest const & cmd,
261                 FuncStatus & flag) const
262 {
263         switch (cmd.action()) {
264         case LFUN_BREAK_PARAGRAPH:
265         case LFUN_LAYOUT:
266         case LFUN_LAYOUT_PARAGRAPH:
267         case LFUN_MATH_DISPLAY:
268         case LFUN_BOX_INSERT:
269         case LFUN_BRANCH_INSERT:
270         case LFUN_CAPTION_INSERT:
271         case LFUN_FLOAT_INSERT:
272         case LFUN_FLOAT_LIST_INSERT:
273         case LFUN_FLOAT_WIDE_INSERT:
274         case LFUN_FOOTNOTE_INSERT:
275         case LFUN_HFILL_INSERT:
276         case LFUN_INDEX_PRINT:
277         case LFUN_LISTING_INSERT:
278         case LFUN_MARGINALNOTE_INSERT:
279         case LFUN_NEWLINE_INSERT:
280         case LFUN_NEWPAGE_INSERT:
281         case LFUN_NOMENCL_PRINT:
282         case LFUN_PREVIEW_INSERT:
283         case LFUN_QUOTE_INSERT:
284         case LFUN_TABULAR_INSERT:
285         case LFUN_WRAP_INSERT:
286                 flag.setEnabled(false);
287                 return true;
288         case LFUN_INSET_MODIFY:
289                 flag.setEnabled(true);
290                 return true;
291         case LFUN_COMMAND_SEQUENCE: {
292                 // argument contains ';'-terminated commands
293                 string arg = to_utf8(cmd.argument());
294                 // prevent insertion of display math formulas like AMS align
295                 while (!arg.empty()) {
296                         string first;
297                         arg = support::split(arg, first, ';');
298                         FuncRequest func(lyxaction.lookupFunc(first));
299                         if (func.action() == LFUN_MATH_MUTATE) {
300                                 flag.setEnabled(false);
301                                 return true;
302                         }
303                 }
304                 break;
305         }
306         default:
307                 break;
308         }
309         return InsetText::getStatus(cur, cmd, flag);
310 }
311
312
313 docstring InsetScript::toolTip(BufferView const &, int, int) const
314 {
315         OutputParams rp(&buffer().params().encoding());
316         odocstringstream ods;
317         InsetText::plaintext(ods, rp);
318         docstring content_tip = ods.str();
319         // shorten it if necessary
320         if (content_tip.size() > 200)
321                 content_tip = content_tip.substr(0, 200) + "...";
322         docstring res = scripttranslator_loc().find(params_.type);
323         if (!content_tip.empty())
324                 res += from_ascii(": ") + content_tip;
325         return res;
326 }
327
328
329 void InsetScript::validate(LaTeXFeatures & features) const
330 {
331         if (params_.type == InsetScriptParams::Subscript)
332                 features.require("subscript");
333         InsetText::validate(features);
334 }
335
336
337 int InsetScript::latex(odocstream & os, OutputParams const & runparams) const
338 {
339         switch (params_.type) {
340         case InsetScriptParams::Subscript:
341                 os << "\\textsubscript{";
342                 break;
343         case InsetScriptParams::Superscript:
344                 os << "\\textsuperscript{";
345                 break;
346         }
347         int const i = InsetText::latex(os, runparams);
348         os << "}";
349
350         return i;
351 }
352
353
354 int InsetScript::plaintext(odocstream & os, OutputParams const & runparams) const
355 {
356         odocstringstream oss;
357         InsetText::plaintext(oss, runparams);
358         docstring const text = oss.str();
359         switch (params_.type) {
360         case InsetScriptParams::Subscript:
361                 if (text.size() == 1) {
362                         char_type const c = support::subscript(text[0]);
363                         if (c != text[0]) {
364                                 os.put(c);
365                                 return 0;
366                         }
367                 }
368                 os << '[' << buffer().B_("subscript") << ':';
369                 break;
370         case InsetScriptParams::Superscript:
371                 if (text.size() == 1) {
372                         char_type const c = support::superscript(text[0]);
373                         if (c != text[0]) {
374                                 os.put(c);
375                                 return 0;
376                         }
377                 }
378                 os << '[' << buffer().B_("superscript") << ':';
379                 break;
380         }
381         InsetText::plaintext(os, runparams);
382         os << ']';
383
384         return PLAINTEXT_NEWLINE;
385 }
386
387
388 int InsetScript::docbook(odocstream & os, OutputParams const & runparams) const
389 {
390         string cmdname;
391         switch (params_.type) {
392         case InsetScriptParams::Subscript:
393                 cmdname = "subscript";
394                 break;
395         case InsetScriptParams::Superscript:
396                 cmdname = "superscript";
397                 break;
398         }
399         os << '<' + cmdname + '>';
400         int const i = InsetText::docbook(os, runparams);
401         os << "</" + cmdname + '>';
402
403         return i;
404 }
405
406
407 docstring InsetScript::xhtml(XHTMLStream & xs, OutputParams const & runparams) const
408 {
409         string cmdname;
410         switch (params_.type) {
411         case InsetScriptParams::Subscript:
412                 cmdname = "sub";
413                 break;
414         case InsetScriptParams::Superscript:
415                 cmdname = "sup";
416                 break;
417         }
418
419         xs << html::StartTag(cmdname);
420         docstring const ret = InsetText::xhtml(xs, runparams);
421         xs << html::EndTag(cmdname);
422         return ret;
423 }
424
425
426 docstring InsetScript::contextMenuName() const
427 {
428         return from_ascii("context-script");
429 }
430
431
432 string InsetScript::params2string(InsetScriptParams const & params)
433 {
434         ostringstream data;
435         data << "script ";
436         params.write(data);
437         return data.str();
438 }
439
440
441 void InsetScript::string2params(string const & in, InsetScriptParams & params)
442 {
443         params = InsetScriptParams();
444
445         if (in.empty())
446                 return;
447
448         istringstream data(in);
449         Lexer lex;
450         lex.setStream(data);
451         lex.setContext("InsetScript::string2params");
452         lex >> "script" >> "script";
453
454         params.read(lex);
455 }
456
457
458 } // namespace lyx