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