]> git.lyx.org Git - lyx.git/blob - src/insets/insetminipage.C
rowlist8
[lyx.git] / src / insets / insetminipage.C
1 /**
2  * \file insetminipage.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jürgen Vigna
7  * \author Lars Gullik Bjønnes
8  *
9  * Full author contact details are available in file CREDITS
10  */
11
12 #include <config.h>
13
14
15 #include "insetminipage.h"
16 #include "insettext.h"
17
18 #include "BufferView.h"
19 #include "debug.h"
20 #include "funcrequest.h"
21 #include "gettext.h"
22 #include "lyxfont.h"
23 #include "lyxlex.h"
24 #include "lyxtext.h"
25
26 #include "frontends/LyXView.h"
27 #include "frontends/Dialogs.h"
28
29 #include "support/LOstream.h"
30 #include "support/lstrings.h"
31
32 using std::ostream;
33 using std::endl;
34
35
36 // Some information about Minipages in LaTeX:
37 // A minipage is a complete miniversion of a page and can contain
38 // its own footnotes, paragraphs, and array, tabular, and multicols
39 // environments. However it cannot contain floats or \marginpar's,
40 // but it can appear inside floats.
41 //
42 // The minipage environment is defined like this:
43 //
44 // \begin{minipage}[pos][height][inner-pos]{width} <text> \end{minipage}
45 //
46 // Where:
47 //     pos [opt] = is the vertical placement of the box with respect
48 //                 to the text baseline, [c], [t] and [b].
49 //     height [opt] = the height of the box
50 //     inner-pos [opt] = the position of the text within the box.
51 //                 It can be t, c, b or s, if unspecified the value
52 //                 of pos is used.
53 //     width = the width of the box
54 //
55 // In LyX we should try to support all these parameters, settable in a
56 // pop-up dialog.
57 // In this pop-up diallog it should also be possible to set all margin
58 // values that is usable in the minipage.
59 // With regard to different formats (like DocBook) I guess a minipage
60 // can be used there also. Perhaps not in the latex way, but we do not
61 // have to output "" for minipages.
62 // (Lgb)
63
64 InsetMinipage::InsetMinipage(BufferParams const & bp)
65         : InsetCollapsable(bp)
66 {
67         setLabel(_("minipage"));
68         LyXFont font(LyXFont::ALL_SANE);
69         font.decSize();
70         font.decSize();
71         font.setColor(LColor::collapsable);
72         setLabelFont(font);
73 #if 0
74         setAutoCollapse(false);
75 #endif
76
77 #if 0
78 #ifdef WITH_WARNINGS
79 #warning Remove this color definitions before 1.2.0 final!
80 #endif
81         // just for experimentation :)
82         setBackgroundColor(LColor::green);
83 #endif
84
85         inset.setFrameColor(0, LColor::blue);
86         setInsetName("Minipage");
87 }
88
89
90 InsetMinipage::InsetMinipage(InsetMinipage const & in, bool same_id)
91         : InsetCollapsable(in, same_id), params_(in.params_)
92 {}
93
94
95 Inset * InsetMinipage::clone(Buffer const &, bool same_id) const
96 {
97         return new InsetMinipage(*const_cast<InsetMinipage *>(this), same_id);
98 }
99
100
101 InsetMinipage::~InsetMinipage()
102 {
103         InsetMinipageMailer mailer(*this);
104         mailer.hideDialog();
105 }
106
107
108 dispatch_result InsetMinipage::localDispatch(FuncRequest const & cmd)
109 {
110         Inset::RESULT result = UNDISPATCHED;
111
112         switch (cmd.action) {
113         case LFUN_INSET_MODIFY: {
114                 InsetMinipage::Params params;
115                 InsetMinipageMailer::string2params(cmd.argument, params);
116
117                 params_.pos   = params.pos;
118                 params_.width = params.width;
119
120                 /* FIXME: I refuse to believe we have to live
121                  * with ugliness like this ... */
122                 LyXText * t = inset.getLyXText(cmd.view());
123                 t->need_break_row = t->rows().begin();
124                 t->fullRebreak();
125                 inset.update(cmd.view(), true);
126                 t->setCursorIntern(t->cursor.par(), t->cursor.pos());
127                 cmd.view()->updateInset(this);
128                 result = DISPATCHED;
129         }
130         break;
131
132         case LFUN_INSET_DIALOG_UPDATE: {
133                 InsetMinipageMailer mailer(*this);
134                 mailer.updateDialog(cmd.view());
135         }
136         break;
137
138         default:
139                 result = InsetCollapsable::localDispatch(cmd);
140         }
141
142         return result;
143 }
144
145
146 void InsetMinipage::Params::write(ostream & os) const
147 {
148         os << "Minipage" << '\n'
149            << "position " << pos << '\n'
150            << "inner_position " << inner_pos << '\n'
151            << "height \"" << height.asString() << "\"\n"
152            << "width \"" << width.asString() << "\"\n";
153 }
154
155
156 void InsetMinipage::Params::read(LyXLex & lex)
157 {
158         if (lex.isOK()) {
159                 lex.next();
160                 string const token = lex.getString();
161                 if (token == "position") {
162                         lex.next();
163                         pos = static_cast<Position>(lex.getInteger());
164                 } else {
165                         lyxerr << "InsetMinipage::Read: Missing 'position'-tag!"
166                                    << endl;
167                         // take countermeasures
168                         lex.pushToken(token);
169                 }
170         }
171         if (lex.isOK()) {
172                 lex.next();
173                 string const token = lex.getString();
174                 if (token == "inner_position") {
175                         lex.next();
176                         inner_pos = static_cast<InnerPosition>(lex.getInteger());
177                 } else {
178                         lyxerr << "InsetMinipage::Read: Missing 'inner_position'-tag!"
179                                    << endl;
180                         // take countermeasures
181                         lex.pushToken(token);
182                 }
183         }
184         if (lex.isOK()) {
185                 lex.next();
186                 string const token = lex.getString();
187                 if (token == "height") {
188                         lex.next();
189                         height = LyXLength(lex.getString());
190                 } else {
191                         lyxerr << "InsetMinipage::Read: Missing 'height'-tag!"
192                                    << endl;
193                         // take countermeasures
194                         lex.pushToken(token);
195                 }
196         }
197         if (lex.isOK()) {
198                 lex.next();
199                 string const token = lex.getString();
200                 if (token == "width") {
201                         lex.next();
202                         width = LyXLength(lex.getString());
203                 } else {
204                         lyxerr << "InsetMinipage::Read: Missing 'width'-tag!"
205                                    << endl;
206                         // take countermeasures
207                         lex.pushToken(token);
208                 }
209         }
210 }
211
212
213 void InsetMinipage::write(Buffer const * buf, ostream & os) const
214 {
215         params_.write(os);
216         InsetCollapsable::write(buf, os);
217 }
218
219
220 void InsetMinipage::read(Buffer const * buf, LyXLex & lex)
221 {
222         params_.read(lex);
223         InsetCollapsable::read(buf, lex);
224 }
225
226
227 int InsetMinipage::ascent(BufferView * bv, LyXFont const & font) const
228 {
229         if (collapsed_)
230                 return ascent_collapsed();
231         else {
232                 // Take placement into account.
233                 int i = 0;
234                 switch (params_.pos) {
235                 case top:
236                         i = InsetCollapsable::ascent(bv, font);
237                         break;
238                 case center:
239                         i = (InsetCollapsable::ascent(bv, font)
240                              + InsetCollapsable::descent(bv, font)) / 2;
241                         break;
242                 case bottom:
243                         i = InsetCollapsable::descent(bv, font);
244                         break;
245                 }
246                 return i;
247         }
248 }
249
250
251 int InsetMinipage::descent(BufferView * bv, LyXFont const & font) const
252 {
253         if (collapsed_)
254                 return descent_collapsed();
255         else {
256                 // Take placement into account.
257                 int i = 0;
258                 switch (params_.pos) {
259                 case top:
260                         i = InsetCollapsable::descent(bv, font);
261                         break;
262                 case center:
263                         i = (InsetCollapsable::ascent(bv, font)
264                              + InsetCollapsable::descent(bv, font)) / 2;
265                         break;
266                 case bottom:
267                         i = InsetCollapsable::ascent(bv, font);
268                         break;
269                 }
270                 return i;
271         }
272 }
273
274
275 string const InsetMinipage::editMessage() const
276 {
277         return _("Opened Minipage Inset");
278 }
279
280
281 int InsetMinipage::latex(Buffer const * buf,
282                          ostream & os, bool fragile, bool fp) const
283 {
284         string s_pos;
285         switch (params_.pos) {
286         case top:
287                 s_pos += 't';
288                 break;
289         case center:
290                 s_pos += 'c';
291                 break;
292         case bottom:
293                 s_pos += 'b';
294                 break;
295         }
296         os << "\\begin{minipage}[" << s_pos << "]{"
297            << params_.width.asLatexString() << "}%\n";
298
299         int i = inset.latex(buf, os, fragile, fp);
300
301         os << "\\end{minipage}%\n";
302         return i + 2;
303 }
304
305
306 bool InsetMinipage::insetAllowed(Inset::Code code) const
307 {
308         if ((code == Inset::FLOAT_CODE) || (code == Inset::MARGIN_CODE))
309                 return false;
310
311         return InsetCollapsable::insetAllowed(code);
312 }
313
314
315 bool InsetMinipage::showInsetDialog(BufferView * bv) const
316 {
317         if (!inset.showInsetDialog(bv)) {
318                 InsetMinipage * tmp = const_cast<InsetMinipage *>(this);
319                 InsetMinipageMailer mailer(*tmp);
320                 mailer.showDialog(bv);
321         }
322
323         return true;
324 }
325
326
327 int InsetMinipage::getMaxWidth(BufferView * bv, UpdatableInset const * inset)
328         const
329 {
330         if (owner() &&
331             static_cast<UpdatableInset*>(owner())->getMaxWidth(bv, inset) < 0) {
332                 return -1;
333         }
334         if (!params_.width.zero()) {
335                 int ww1 = latexTextWidth(bv);
336                 int ww2 = InsetCollapsable::getMaxWidth(bv, inset);
337                 if (ww2 > 0 && ww2 < ww1) {
338                         return ww2;
339                 }
340                 return ww1;
341         }
342         // this should not happen!
343         return InsetCollapsable::getMaxWidth(bv, inset);
344 }
345
346
347 int InsetMinipage::latexTextWidth(BufferView * bv) const
348 {
349         return params_.width.inPixels(InsetCollapsable::latexTextWidth(bv));
350 }
351
352
353 InsetMinipage::Params::Params()
354         : pos(center),
355           inner_pos(inner_center),
356           width(100, LyXLength::PCW)
357 {}
358
359
360 string const InsetMinipageMailer:: name_("minipage");
361
362 InsetMinipageMailer::InsetMinipageMailer(InsetMinipage & inset)
363         : inset_(inset)
364 {}
365
366
367 string const InsetMinipageMailer::inset2string() const
368 {
369         return params2string(inset_.params());
370 }
371
372
373 void InsetMinipageMailer::string2params(string const & in,
374                                         InsetMinipage::Params & params)
375 {
376         params = InsetMinipage::Params();
377
378         istringstream data(in);
379         LyXLex lex(0,0);
380         lex.setStream(data);
381
382         if (lex.isOK()) {
383                 lex.next();
384                 string const token = lex.getString();
385                 if (token != "minipage")
386                         return;
387         }
388
389         // This is part of the inset proper that is usually swallowed
390         // by Buffer::readInset
391         if (lex.isOK()) {
392                 lex.next();
393                 string const token = lex.getString();
394                 if (token != "Minipage")
395                         return;
396         }
397
398         if (lex.isOK()) {
399                 params.read(lex);
400         }
401 }
402
403
404 string const
405 InsetMinipageMailer::params2string(InsetMinipage::Params const & params)
406 {
407         ostringstream data;
408         data << name_ << ' ';
409         params.write(data);
410
411         return data.str();
412 }