]> git.lyx.org Git - lyx.git/blob - src/insets/insetminipage.C
My patch from yesterday
[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: what magical mysterious commands are actually
121                 // needed here to update the bloody size of the inset !!!
122                 cmd.view()->updateInset(this);
123                 result = DISPATCHED;
124         }
125         break;
126
127         case LFUN_INSET_DIALOG_UPDATE: {
128                 InsetMinipageMailer mailer(*this);
129                 mailer.updateDialog(cmd.view());
130         }
131         break;
132
133         default:
134                 result = InsetCollapsable::localDispatch(cmd);
135         }
136
137         return result;
138 }
139
140
141 void InsetMinipage::Params::write(ostream & os) const
142 {
143         os << "Minipage" << '\n'
144            << "position " << pos << '\n'
145            << "inner_position " << inner_pos << '\n'
146            << "height \"" << height.asString() << "\"\n"
147            << "width \"" << width.asString() << "\"\n";
148 }
149
150
151 void InsetMinipage::Params::read(LyXLex & lex)
152 {
153         if (lex.isOK()) {
154                 lex.next();
155                 string const token = lex.getString();
156                 if (token == "position") {
157                         lex.next();
158                         pos = static_cast<Position>(lex.getInteger());
159                 } else {
160                         lyxerr << "InsetMinipage::Read: Missing 'position'-tag!"
161                                    << endl;
162                         // take countermeasures
163                         lex.pushToken(token);
164                 }
165         }
166         if (lex.isOK()) {
167                 lex.next();
168                 string const token = lex.getString();
169                 if (token == "inner_position") {
170                         lex.next();
171                         inner_pos = static_cast<InnerPosition>(lex.getInteger());
172                 } else {
173                         lyxerr << "InsetMinipage::Read: Missing 'inner_position'-tag!"
174                                    << endl;
175                         // take countermeasures
176                         lex.pushToken(token);
177                 }
178         }
179         if (lex.isOK()) {
180                 lex.next();
181                 string const token = lex.getString();
182                 if (token == "height") {
183                         lex.next();
184                         height = LyXLength(lex.getString());
185                 } else {
186                         lyxerr << "InsetMinipage::Read: Missing 'height'-tag!"
187                                    << endl;
188                         // take countermeasures
189                         lex.pushToken(token);
190                 }
191         }
192         if (lex.isOK()) {
193                 lex.next();
194                 string const token = lex.getString();
195                 if (token == "width") {
196                         lex.next();
197                         width = LyXLength(lex.getString());
198                 } else {
199                         lyxerr << "InsetMinipage::Read: Missing 'width'-tag!"
200                                    << endl;
201                         // take countermeasures
202                         lex.pushToken(token);
203                 }
204         }
205 }
206
207
208 void InsetMinipage::write(Buffer const * buf, ostream & os) const
209 {
210         params_.write(os);
211         InsetCollapsable::write(buf, os);
212 }
213
214
215 void InsetMinipage::read(Buffer const * buf, LyXLex & lex)
216 {
217         params_.read(lex);
218         InsetCollapsable::read(buf, lex);
219 }
220
221
222 int InsetMinipage::ascent(BufferView * bv, LyXFont const & font) const
223 {
224         if (collapsed_)
225                 return ascent_collapsed();
226         else {
227                 // Take placement into account.
228                 int i = 0;
229                 switch (params_.pos) {
230                 case top:
231                         i = InsetCollapsable::ascent(bv, font);
232                         break;
233                 case center:
234                         i = (InsetCollapsable::ascent(bv, font)
235                              + InsetCollapsable::descent(bv, font)) / 2;
236                         break;
237                 case bottom:
238                         i = InsetCollapsable::descent(bv, font);
239                         break;
240                 }
241                 return i;
242         }
243 }
244
245
246 int InsetMinipage::descent(BufferView * bv, LyXFont const & font) const
247 {
248         if (collapsed_)
249                 return descent_collapsed();
250         else {
251                 // Take placement into account.
252                 int i = 0;
253                 switch (params_.pos) {
254                 case top:
255                         i = InsetCollapsable::descent(bv, font);
256                         break;
257                 case center:
258                         i = (InsetCollapsable::ascent(bv, font)
259                              + InsetCollapsable::descent(bv, font)) / 2;
260                         break;
261                 case bottom:
262                         i = InsetCollapsable::ascent(bv, font);
263                         break;
264                 }
265                 return i;
266         }
267 }
268
269
270 string const InsetMinipage::editMessage() const
271 {
272         return _("Opened Minipage Inset");
273 }
274
275
276 int InsetMinipage::latex(Buffer const * buf,
277                          ostream & os, bool fragile, bool fp) const
278 {
279         string s_pos;
280         switch (params_.pos) {
281         case top:
282                 s_pos += 't';
283                 break;
284         case center:
285                 s_pos += 'c';
286                 break;
287         case bottom:
288                 s_pos += 'b';
289                 break;
290         }
291         os << "\\begin{minipage}[" << s_pos << "]{"
292            << params_.width.asLatexString() << "}%\n";
293
294         int i = inset.latex(buf, os, fragile, fp);
295
296         os << "\\end{minipage}%\n";
297         return i + 2;
298 }
299
300
301 bool InsetMinipage::insetAllowed(Inset::Code code) const
302 {
303         if ((code == Inset::FLOAT_CODE) || (code == Inset::MARGIN_CODE))
304                 return false;
305
306         return InsetCollapsable::insetAllowed(code);
307 }
308
309
310 bool InsetMinipage::showInsetDialog(BufferView * bv) const
311 {
312         if (!inset.showInsetDialog(bv)) {
313                 InsetMinipage * tmp = const_cast<InsetMinipage *>(this);
314                 InsetMinipageMailer mailer(*tmp);
315                 mailer.showDialog(bv);
316         }
317
318         return true;
319 }
320
321
322 int InsetMinipage::getMaxWidth(BufferView * bv, UpdatableInset const * inset)
323         const
324 {
325         if (owner() &&
326             static_cast<UpdatableInset*>(owner())->getMaxWidth(bv, inset) < 0) {
327                 return -1;
328         }
329         if (!params_.width.zero()) {
330                 int ww1 = latexTextWidth(bv);
331                 int ww2 = InsetCollapsable::getMaxWidth(bv, inset);
332                 if (ww2 > 0 && ww2 < ww1) {
333                         return ww2;
334                 }
335                 return ww1;
336         }
337         // this should not happen!
338         return InsetCollapsable::getMaxWidth(bv, inset);
339 }
340
341
342 int InsetMinipage::latexTextWidth(BufferView * bv) const
343 {
344         return params_.width.inPixels(InsetCollapsable::latexTextWidth(bv));
345 }
346
347
348 InsetMinipage::Params::Params()
349         : pos(center),
350           inner_pos(inner_center),
351           width(100, LyXLength::PCW)
352 {}
353
354
355 string const InsetMinipageMailer:: name_("minipage");
356
357 InsetMinipageMailer::InsetMinipageMailer(InsetMinipage & inset)
358         : inset_(inset)
359 {}
360
361
362 string const InsetMinipageMailer::inset2string() const
363 {
364         return params2string(inset_.params());
365 }
366
367
368 void InsetMinipageMailer::string2params(string const & in,
369                                         InsetMinipage::Params & params)
370 {
371         params = InsetMinipage::Params();
372
373         istringstream data(in);
374         LyXLex lex(0,0);
375         lex.setStream(data);
376
377         if (lex.isOK()) {
378                 lex.next();
379                 string const token = lex.getString();
380                 if (token != "minipage")
381                         return;
382         }
383
384         // This is part of the inset proper that is usually swallowed
385         // by Buffer::readInset
386         if (lex.isOK()) {
387                 lex.next();
388                 string const token = lex.getString();
389                 if (token != "Minipage")
390                         return;
391         }
392
393         if (lex.isOK()) {
394                 params.read(lex);
395         }
396 }
397
398
399 string const
400 InsetMinipageMailer::params2string(InsetMinipage::Params const & params)
401 {
402         ostringstream data;
403         data << name_ << ' ';
404         params.write(data);
405
406         return data.str();
407 }