]> git.lyx.org Git - lyx.git/blob - src/insets/InsetCharStyle.cpp
Further inset configurability, moving charstyle stuff to collapsable
[lyx.git] / src / insets / InsetCharStyle.cpp
1 /**
2  * \file InsetCharStyle.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming
7  * \author Martin Vermeer
8  * \author Jürgen Spitzmüller
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "InsetCharStyle.h"
16
17 #include "Buffer.h"
18 #include "BufferParams.h"
19 #include "BufferView.h"
20 #include "DispatchResult.h"
21 #include "FuncRequest.h"
22 #include "FuncStatus.h"
23 #include "Cursor.h"
24 #include "gettext.h"
25 #include "LaTeXFeatures.h"
26 #include "Color.h"
27 #include "Lexer.h"
28 #include "Text.h"
29 #include "MetricsInfo.h"
30 #include "Paragraph.h"
31 #include "paragraph_funcs.h"
32 #include "sgml.h"
33
34 #include "frontends/FontMetrics.h"
35 #include "frontends/Painter.h"
36
37 #include "support/convert.h"
38
39 #include <sstream>
40
41
42 namespace lyx {
43
44 using std::string;
45 using std::auto_ptr;
46 using std::istringstream;
47 using std::max;
48 using std::ostream;
49 using std::ostringstream;
50
51
52 void InsetCharStyle::init()
53 {}
54
55
56 InsetCharStyle::InsetCharStyle(BufferParams const & bp, string const s)
57         : InsetCollapsable(bp, Collapsed)
58 {
59         params_.type = s;
60         setUndefined();
61         init();
62 }
63
64
65 InsetCharStyle::InsetCharStyle(BufferParams const & bp,
66                                 CharStyles::iterator cs)
67         : InsetCollapsable(bp, Collapsed)
68 {
69         params_.type = cs->name;
70         setDefined(cs);
71         init();
72 }
73
74
75 InsetCharStyle::InsetCharStyle(InsetCharStyle const & in)
76         : InsetCollapsable(in), params_(in.params_)
77 {
78         init();
79 }
80
81
82 auto_ptr<Inset> InsetCharStyle::doClone() const
83 {
84         return auto_ptr<Inset>(new InsetCharStyle(*this));
85 }
86
87
88 bool InsetCharStyle::undefined() const
89 {
90         return params_.latexname.empty();
91 }
92
93
94 void InsetCharStyle::setUndefined()
95 {
96         params_.latextype.clear();
97         params_.latexname.clear();
98         params_.latexparam.clear();
99         params_.font = Font(Font::ALL_INHERIT);
100         params_.labelfont = Font(Font::ALL_INHERIT);
101         params_.labelfont.setColor(Color::error);
102 }
103
104
105 void InsetCharStyle::setDefined(CharStyles::iterator cs)
106 {
107         params_.latextype = cs->latextype;
108         params_.latexname = cs->latexname;
109         params_.latexparam = cs->latexparam;
110         params_.font = cs->font;
111         params_.labelfont = cs->labelfont;
112 }
113
114
115 docstring const InsetCharStyle::editMessage() const
116 {
117         return _("Opened CharStyle Inset");
118 }
119
120
121 void InsetCharStyle::write(Buffer const & buf, ostream & os) const
122 {
123         params_.write(os);
124         InsetCollapsable::write(buf, os);
125 }
126
127
128 void InsetCharStyle::read(Buffer const & buf, Lexer & lex)
129 {
130         params_.read(lex);
131         InsetCollapsable::read(buf, lex);
132 }
133
134
135 bool InsetCharStyle::metrics(MetricsInfo & mi, Dimension & dim) const
136 {
137         Font tmpfont = mi.base.font;
138         getDrawFont(mi.base.font);
139         mi.base.font.reduce(Font(Font::ALL_SANE));
140         mi.base.font.realize(tmpfont);
141         mi.base.textwidth -= 2 * TEXT_TO_INSET_OFFSET;
142         InsetText::metrics(mi, dim);
143         mi.base.font = tmpfont;
144         if (status() == Open) {
145                 // consider width of the inset label
146                 Font font(params_.labelfont);
147                 font.realize(Font(Font::ALL_SANE));
148                 font.decSize();
149                 font.decSize();
150                 int w = 0;
151                 int a = 0;
152                 int d = 0;
153                 // FIXME UNICODE
154                 docstring s(from_utf8(params_.type));
155                 if (undefined())
156                         s = _("Undef: ") + s;
157                 // Chop off prefix:
158                 if (s.find(':') != string::npos)
159                         s = s.substr(s.find(':'));
160                 theFontMetrics(font).rectText(s, w, a, d);
161                 dim.wid = max(dim.wid, w);
162         }
163         dim.asc += TEXT_TO_INSET_OFFSET;
164         dim.des += TEXT_TO_INSET_OFFSET;
165         dim.wid += 2 * TEXT_TO_INSET_OFFSET;
166         mi.base.textwidth += 2 * TEXT_TO_INSET_OFFSET;
167         if (status() == Open)
168                 dim.des += ascent();
169         else {
170                 dim.des -= 3;
171                 dim.asc -= 3;
172         }
173         bool const changed =  dim_ != dim;
174         dim_ = dim;
175         return changed;
176 }
177
178
179 void InsetCharStyle::draw(PainterInfo & pi, int x, int y) const
180 {
181         setPosCache(pi, x, y);
182
183         Font tmpfont = pi.base.font;
184         getDrawFont(pi.base.font);
185         // I don't understand why the above .reduce and .realize aren't
186         //needed, or even wanted, here. It just works. -- MV 10.04.2005
187         InsetCollapsable::draw(pi, x, y);
188         pi.base.font = tmpfont;
189
190         int desc = InsetText::descent();
191         if (status() == Open)
192                 desc -= ascent();
193         else
194                 desc -= 3;
195
196         pi.pain.line(x, y + desc - 4, x, y + desc, params_.labelfont.color());
197         pi.pain.line(x, y + desc, x + dim_.wid - 3, y + desc,
198                 params_.labelfont.color());
199         pi.pain.line(x + dim_.wid - 3, y + desc, x + dim_.wid - 3, y + desc - 4,
200                 params_.labelfont.color());
201
202         // the name of the charstyle. Can be toggled.
203         if (status() == Open) {
204                 Font font(params_.labelfont);
205                 font.realize(Font(Font::ALL_SANE));
206                 font.decSize();
207                 font.decSize();
208                 int w = 0;
209                 int a = 0;
210                 int d = 0;
211                 // FIXME UNICODE
212                 docstring s(from_utf8(params_.type));
213                 if (undefined())
214                         s = _("Undef: ") + s;
215                 // Chop off prefix:
216                 if (s.find(':') != string::npos)
217                         s = s.substr(s.find(':'));
218                 theFontMetrics(font).rectText(s, w, a, d);
219                 pi.pain.rectText(x + (dim_.wid - w) / 2, y + desc + a,
220                         s, font, Color::none, Color::none);
221         }
222
223         // a visual cue when the cursor is inside the inset
224         Cursor & cur = pi.base.bv->cursor();
225         if (cur.isInside(this)) {
226                 y -= ascent();
227                 y += 3;
228                 pi.pain.line(x, y + 4, x, y, params_.labelfont.color());
229                 pi.pain.line(x + 4, y, x, y, params_.labelfont.color());
230                 pi.pain.line(x + dim_.wid - 3, y + 4, x + dim_.wid - 3, y,
231                         params_.labelfont.color());
232                 pi.pain.line(x + dim_.wid - 7, y, x + dim_.wid - 3, y,
233                         params_.labelfont.color());
234         }
235 }
236
237
238 void InsetCharStyle::getDrawFont(Font & font) const
239 {
240         font = params_.font;
241 }
242
243
244 void InsetCharStyle::doDispatch(Cursor & cur, FuncRequest & cmd)
245 {
246         switch (cmd.action) {
247
248         case LFUN_MOUSE_RELEASE:
249                         if (cmd.button() == mouse_button::button3)
250                                 if (status() == Open)
251                                         setStatus(cur, Collapsed);
252                                 else
253                                         setStatus(cur, Open);
254                         else
255                                 InsetCollapsable::doDispatch(cur, cmd);
256                         break;
257
258         case LFUN_INSET_TOGGLE:
259                 if (cmd.argument() == "open")
260                         setStatus(cur, Open);
261                 else if (cmd.argument() == "close")
262                         setStatus(cur, Collapsed);
263                 else if (cmd.argument() == "toggle" || cmd.argument().empty())
264                         if (status() == Open)
265                                 setStatus(cur, Collapsed);
266                         else
267                                 setStatus(cur, Open);
268                 else // if assign or anything else
269                         cur.undispatched();
270                 cur.dispatched();
271                 break;
272
273         default:
274                 InsetCollapsable::doDispatch(cur, cmd);
275                 break;
276         }
277 }
278
279
280 bool InsetCharStyle::getStatus(Cursor & cur, FuncRequest const & cmd,
281         FuncStatus & status) const
282 {
283         switch (cmd.action) {
284                 // paragraph breaks not allowed in charstyle insets
285                 case LFUN_BREAK_PARAGRAPH:
286                 case LFUN_BREAK_PARAGRAPH_KEEP_LAYOUT:
287                 case LFUN_BREAK_PARAGRAPH_SKIP:
288                         status.enabled(false);
289                         return true;
290
291                 default:
292                         return InsetCollapsable::getStatus(cur, cmd, status);
293                 }
294 }
295
296
297 int InsetCharStyle::latex(Buffer const & buf, odocstream & os,
298                           OutputParams const & runparams) const
299 {
300         if (!undefined()) {
301                 // FIXME UNICODE
302                 os << '\\' << from_utf8(params_.latexname);
303                 if (!params_.latexparam.empty())
304                         os << from_utf8(params_.latexparam);
305                 os << '{';
306         }
307         int i = InsetText::latex(buf, os, runparams);
308         if (!undefined())
309                 os << "}";
310         return i;
311 }
312
313
314 int InsetCharStyle::plaintext(Buffer const & buf, odocstream & os,
315                               OutputParams const & runparams) const
316 {
317         return InsetText::plaintext(buf, os, runparams);
318 }
319
320
321 int InsetCharStyle::docbook(Buffer const & buf, odocstream & os,
322                             OutputParams const & runparams) const
323 {
324         ParagraphList::const_iterator beg = paragraphs().begin();
325         ParagraphList::const_iterator par = paragraphs().begin();
326         ParagraphList::const_iterator end = paragraphs().end();
327
328         if (!undefined())
329                 // FIXME UNICODE
330                 sgml::openTag(os, params_.latexname,
331                               par->getID(buf, runparams) + params_.latexparam);
332
333         for (; par != end; ++par) {
334                 par->simpleDocBookOnePar(buf, os, runparams,
335                                          outerFont(std::distance(beg, par),
336                                                    paragraphs()));
337         }
338
339         if (!undefined())
340                 sgml::closeTag(os, params_.latexname);
341
342         return 0;
343 }
344
345
346 void InsetCharStyle::textString(Buffer const & buf, odocstream & os) const
347 {
348         os << paragraphs().begin()->asString(buf, true);
349 }
350
351
352 void InsetCharStyle::validate(LaTeXFeatures & features) const
353 {
354         // Force inclusion of preamble snippet in layout file
355         features.require(params_.type);
356         InsetText::validate(features);
357 }
358
359
360 void InsetCharStyleParams::write(ostream & os) const
361 {
362         os << "CharStyle " << type << "\n";
363 }
364
365
366 void InsetCharStyleParams::read(Lexer & lex)
367 {
368         while (lex.isOK()) {
369                 lex.next();
370                 string token = lex.getString();
371
372                 if (token == "CharStyle") {
373                         lex.next();
374                         type = lex.getString();
375                 }
376
377                 // This is handled in Collapsable
378                 else if (token == "status") {
379                         lex.pushToken(token);
380                         break;
381                 }
382         }
383 }
384
385
386 } // namespace lyx