]> git.lyx.org Git - lyx.git/blob - src/insets/insetbox.C
The Box patch
[lyx.git] / src / insets / insetbox.C
1 /**
2  * \file insetbox.C
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 "insetbox.h"
16 #include "debug.h"
17
18 #include "BufferView.h"
19 #include "funcrequest.h"
20 #include "gettext.h"
21 #include "LaTeXFeatures.h"
22 #include "LColor.h"
23 #include "lyxlex.h"
24 #include "metricsinfo.h"
25 #include "paragraph.h"
26
27 #include "support/std_sstream.h"
28
29 using std::auto_ptr;
30 using std::string;
31 using std::istringstream;
32 using std::ostream;
33 using std::ostringstream;
34 using std::endl;
35
36
37 namespace {
38
39 BoxTranslator const init_boxtranslator() {
40         BoxTranslator translator("Boxed", InsetBox::Boxed);
41         translator.addPair("Frameless", InsetBox::Frameless);
42         translator.addPair("ovalbox", InsetBox::ovalbox);
43         translator.addPair("Ovalbox", InsetBox::Ovalbox);
44         translator.addPair("Shadowbox", InsetBox::Shadowbox);
45         translator.addPair("Doublebox",InsetBox::Doublebox);
46         return translator;
47 }
48
49
50 BoxTranslator const init_boxtranslator_loc() {
51         BoxTranslator translator(_("Boxed"), InsetBox::Boxed);
52         translator.addPair(_("Frameless"), InsetBox::Frameless);
53         translator.addPair(_("ovalbox"), InsetBox::ovalbox);
54         translator.addPair(_("Ovalbox"), InsetBox::Ovalbox);
55         translator.addPair(_("Shadowbox"), InsetBox::Shadowbox);
56         translator.addPair(_("Doublebox"), InsetBox::Doublebox);
57         return translator;
58 }
59
60
61 BoxTranslator const & boxtranslator() {
62         static BoxTranslator translator = init_boxtranslator();
63         return translator;
64 }
65
66
67 BoxTranslator const & boxtranslator_loc() {
68         static BoxTranslator translator = init_boxtranslator_loc();
69         return translator;
70 }
71
72 } // anon
73
74
75 void InsetBox::init()
76 {
77         setInsetName("Box");
78         setButtonLabel();
79 }
80
81
82 InsetBox::InsetBox(BufferParams const & bp, string const & label)
83         : InsetCollapsable(bp), params_(label)
84 {
85         init();
86 }
87
88
89 InsetBox::InsetBox(InsetBox const & in)
90         : InsetCollapsable(in), params_(in.params_)
91 {
92         init();
93 }
94
95
96 InsetBox::~InsetBox()
97 {
98         InsetBoxMailer mailer(*this);
99         mailer.hideDialog();
100 }
101
102
103 auto_ptr<InsetBase> InsetBox::clone() const
104 {
105         return auto_ptr<InsetBase>(new InsetBox(*this));
106 }
107
108
109 string const InsetBox::editMessage() const
110 {
111         return _("Opened Box Inset");
112 }
113
114
115 void InsetBox::write(Buffer const & buf, ostream & os) const
116 {
117         params_.write(os);
118         InsetCollapsable::write(buf, os);
119 }
120
121
122 void InsetBox::read(Buffer const & buf, LyXLex & lex)
123 {
124         params_.read(lex);
125         InsetCollapsable::read(buf, lex);
126         setButtonLabel();
127 }
128
129
130 void InsetBox::setButtonLabel()
131 {
132         LyXFont font(LyXFont::ALL_SANE);
133         font.decSize();
134         font.decSize();
135
136         BoxType btype = boxtranslator().find(params_.type);
137         if (btype == Frameless) {
138                 if (params_.use_parbox)
139                         setLabel(_("Parbox"));
140                 else
141                         setLabel(_("Minipage"));
142         } else
143                 setLabel(boxtranslator_loc().find(btype));
144
145         font.setColor(LColor::foreground);
146         setBackgroundColor(LColor::background);
147         setLabelFont(font);
148 }
149
150
151 void InsetBox::metrics(MetricsInfo & mi, Dimension & dim) const
152 {
153         InsetCollapsable::metrics(mi, dim);
154         if (params_.inner_box && isOpen())
155                 dim.wid = mi.base.textwidth;
156         dim_ = dim;
157 }
158
159
160 bool InsetBox::showInsetDialog(BufferView * bv) const
161 {
162         InsetBoxMailer(const_cast<InsetBox &>(*this)).showDialog(bv);
163         return true;
164 }
165
166
167 dispatch_result InsetBox::localDispatch(FuncRequest const & cmd)
168 {
169         BufferView * bv = cmd.view();
170
171         switch (cmd.action) {
172
173         case LFUN_INSET_MODIFY: {
174                 InsetBoxMailer::string2params(cmd.argument, params_);
175                 setButtonLabel();
176                 bv->updateInset(this);
177                 return DISPATCHED;
178         }
179         case LFUN_INSET_DIALOG_UPDATE:
180                 InsetBoxMailer(*this).updateDialog(bv);
181                 return DISPATCHED;
182
183         case LFUN_MOUSE_RELEASE:
184                 if (cmd.button() == mouse_button::button3 && hitButton(cmd)) {
185                         InsetBoxMailer(*this).showDialog(bv);
186                         return DISPATCHED;
187                 }
188                 // fallthrough:
189
190         default:
191                 return InsetCollapsable::localDispatch(cmd);
192         }
193 }
194
195
196 int InsetBox::latex(Buffer const & buf, ostream & os,
197                                 LatexRunParams const & runparams) const
198 {
199         BoxType btype = boxtranslator().find(params_.type);
200
201         string width_string = params_.width.asLatexString();
202         bool stdwidth(false);
203         if (params_.inner_box &&
204                         (width_string.find("1.0\\columnwidth") != string::npos
205                         || width_string.find("1.0\\textwidth") != string::npos)) {
206                 stdwidth = true;
207                 switch (btype) {
208                 case Frameless:
209                         break;
210                 case Boxed:
211                         width_string += " - 2\\fboxsep - 2\\fboxrule";
212                         break;
213                 case ovalbox:
214                         width_string += " - 2\\fboxsep - 0.8pt";
215                         break;
216                 case Ovalbox:
217                         width_string += " - 2\\fboxsep - 1.6pt";
218                         break;
219                 case Shadowbox:
220                         // Shadow falls outside right margin... opinions?
221                         width_string += " - 2\\fboxsep - 2\\fboxrule"/* "-\\shadowsize"*/;
222                         break;
223                 case Doublebox:
224                         width_string += " - 2\\fboxsep - 7.5\\fboxrule - 1.0pt";
225                         break;
226                 }
227         }
228         
229         int i = 0;
230         os << "%\n";
231         // Adapt to column/text width correctly also if paragraphs indented:
232         if (stdwidth)
233                 os << "\\noindent";
234         
235         switch (btype) {
236         case Frameless:
237                 break;
238         case Boxed:
239                 os << "\\framebox";
240                 if (!params_.inner_box) {
241                         os << "{\\makebox";
242                         // Special widths, see usrguide §3.5
243                         if (params_.special != "none") {
244                                 os << "[" << params_.width.value()
245                                    << "\\" << params_.special << "]";
246                         } else
247                                 os << "[" << width_string << "]";
248                         if (params_.hor_pos != 'c')
249                                 os << "[" << params_.hor_pos << "]";
250                 }
251                 
252                 os << "{";
253                 break;
254         case ovalbox:
255                 os << "\\ovalbox{";
256                 break;
257         case Ovalbox:
258                 os << "\\Ovalbox{";
259                 break;
260         case Shadowbox:
261                 os << "\\shadowbox{";
262                 break;
263         case Doublebox:
264                 os << "\\doublebox{";
265                 break;
266         }
267
268         if (params_.inner_box) {
269                 if (params_.use_parbox)
270                         os << "\\parbox";
271                 else
272                         os << "\\begin{minipage}";
273
274                 os << "[" << params_.pos << "]";
275                 if (params_.height_special == "none") {
276                         os << "[" << params_.height.asLatexString() << "]";
277                 } else {
278                         // Special heights
279                         os << "[" << params_.height.value()
280                            << "\\" << params_.height_special << "]";
281                 }
282                 if (params_.inner_pos != params_.pos)
283                         os << "[" << params_.inner_pos << "]";
284
285                 os << "{" << width_string << "}";
286
287                 if (params_.use_parbox)
288                         os << "{";
289                 os << "%\n";
290                 i += 1;
291         }
292
293         i += inset.latex(buf, os, runparams);
294
295         if (params_.inner_box) {
296                 if (params_.use_parbox)
297                         os << "%\n}";
298                 else
299                         os << "%\n\\end{minipage}";
300         }
301         
302         switch (btype) {
303         case Frameless:
304                 break;
305         case Boxed:
306                 if (!params_.inner_box)
307                         os << "}"; // for makebox
308                 os << "}";
309                 break;
310         case ovalbox:
311         case Ovalbox:
312         case Doublebox:
313         case Shadowbox:
314                 os << "}";
315                 break;
316         }       
317         os << "%\n";
318         
319         i += 3;
320
321         return i;
322 }
323
324
325 int InsetBox::linuxdoc(Buffer const & buf, std::ostream & os) const
326 {
327         return inset.linuxdoc(buf, os);
328 }
329
330
331 int InsetBox::docbook(Buffer const & buf, std::ostream & os, bool mixcont) const
332 {
333         return inset.docbook(buf, os, mixcont);
334 }
335
336
337 int InsetBox::ascii(Buffer const & buf, std::ostream & os, int ll) const
338 {
339         int i = 0;
340         string const pt = params_.type;
341         BoxType btype = boxtranslator().find(params_.type);
342         switch (btype) {
343                 case Frameless:
344                 break;
345                 case Boxed:
346                 os << "[";
347                 break;
348                 case ovalbox:
349                 os << "(";
350                 break;
351                 case Ovalbox:
352                 os << "((";
353                 break;
354                 case Shadowbox:
355                 os << "[";
356                 break;
357                 case Doublebox:
358                 os << "[[";
359                 break;
360         }
361
362         i = inset.ascii(buf, os, ll);
363
364         switch (btype) {
365                 case Frameless:
366                 break;
367                 case Boxed:
368                 os << "]";
369                 break;
370                 case ovalbox:
371                 os << ")";
372                 break;
373                 case Ovalbox:
374                 os << "))";
375                 break;
376                 case Shadowbox:
377                 os << "]/";
378                 break;
379                 case Doublebox:
380                 os << "]]";
381                 break;
382         }
383
384         return i;
385 }
386
387
388 void InsetBox::validate(LaTeXFeatures & features) const
389 {
390         features.require("calc");
391         BoxType btype = boxtranslator().find(params_.type);
392         switch (btype) {
393         case Frameless:
394         case Boxed:
395                 break;
396         case ovalbox:
397         case Ovalbox:
398         case Shadowbox:
399         case Doublebox:
400                 features.require("fancybox");
401                 break;
402         }
403         inset.validate(features);
404 }
405
406
407 InsetBoxMailer::InsetBoxMailer(InsetBox & inset)
408         : inset_(inset)
409 {
410 }
411
412
413 string const InsetBoxMailer::name_ = "box";
414
415
416 string const InsetBoxMailer::inset2string(Buffer const &) const
417 {
418         return params2string(inset_.params());
419 }
420
421
422 string const InsetBoxMailer::params2string(InsetBoxParams const & params)
423 {
424         ostringstream data;
425         data << "box" << ' ';
426         params.write(data);
427         return data.str();
428 }
429
430
431 void InsetBoxMailer::string2params(string const & in,
432         InsetBoxParams & params)
433 {
434         params = InsetBoxParams(string());
435
436         if (in.empty())
437                 return;
438
439         istringstream data(in);
440         LyXLex lex(0,0);
441         lex.setStream(data);
442
443         string token;
444         lex.next();
445         token = lex.getString();
446         lex.next();
447
448         params.read(lex);
449 }
450
451
452 InsetBoxParams::InsetBoxParams(string const & label)
453         : type(label),
454           use_parbox(false),
455           inner_box(true),
456           width(LyXLength("100col%")),
457           special("none"),
458           pos('t'),
459           hor_pos('c'),
460           inner_pos('t'),
461           height(LyXLength("1in")),
462           height_special("totalheight") // default is 1\\totalheight
463 {}
464
465
466 void InsetBoxParams::write(ostream & os) const
467 {
468         os << type << "\n";
469         os << "position \"" << pos << "\"\n";
470         os << "hor_pos \"" << hor_pos << "\"\n";
471         os << "has_inner_box " << inner_box << "\n";
472         os << "inner_pos \"" << inner_pos << "\"\n";
473         os << "use_parbox " << use_parbox << "\n";
474         os << "width \"" << width.asString() << "\"\n";
475         os << "special \"" << special << "\"\n";
476         os << "height \"" << height.asString() << "\"\n";
477         os << "height_special \"" << height_special << "\"\n";
478 }
479
480
481 void InsetBoxParams::read(LyXLex & lex)
482 {
483         if (lex.isOK()) {
484                 type = lex.getString();
485         }
486         string token;
487         if (!lex.isOK())
488                 return;
489         lex.next();
490         token = lex.getString();
491         if (token == "position") {
492                 lex.next();
493                 // The [0] is needed. We need the first and only char in
494                 // this string -- MV
495                 pos = lex.getString()[0];
496         } else {
497                 lyxerr << "InsetBox::Read: Missing 'position'-tag!" << token << endl;
498                 lex.pushToken(token);
499         }
500         if (!lex.isOK())
501                 return;
502         lex.next();
503         token = lex.getString();
504         if (token == "hor_pos") {
505                 lex.next();
506                 hor_pos = lex.getString()[0];
507         } else {
508                 lyxerr << "InsetBox::Read: Missing 'hor_pos'-tag!" << token << endl;
509                 lex.pushToken(token);
510         }
511         if (!lex.isOK())
512                 return;
513         lex.next();
514         token = lex.getString();
515         if (token == "has_inner_box") {
516                 lex.next();
517                 inner_box = lex.getInteger();
518         } else {
519                 lyxerr << "InsetBox::Read: Missing 'has_inner_box'-tag!" << endl;
520                 lex.pushToken(token);
521         }
522
523         if (!lex.isOK())
524                 return;
525         lex.next();
526         token = lex.getString();
527         if (token == "inner_pos") {
528                 lex.next();
529                 inner_pos = lex.getString()[0];
530         } else {
531                 lyxerr << "InsetBox::Read: Missing 'inner_pos'-tag!"
532                         << token << endl;
533                 lex.pushToken(token);
534         }
535         if (!lex.isOK())
536                 return;
537         lex.next();
538         token = lex.getString();
539         if (token == "use_parbox") {
540                 lex.next();
541                 use_parbox = lex.getInteger();
542         } else {
543                 lyxerr << "InsetBox::Read: Missing 'use_parbox'-tag!" << endl;
544                 lex.pushToken(token);
545         }
546         if (!lex.isOK())
547                 return;
548         lex.next();
549         token = lex.getString();
550         if (token == "width") {
551                 lex.next();
552                 width = LyXLength(lex.getString());
553         } else {
554                 lyxerr << "InsetBox::Read: Missing 'width'-tag!" << endl;
555                 lex.pushToken(token);
556         }
557         if (!lex.isOK())
558                 return;
559         lex.next();
560         token = lex.getString();
561         if (token == "special") {
562                 lex.next();
563                 special = lex.getString();
564         } else {
565                 lyxerr << "InsetBox::Read: Missing 'special'-tag!" << endl;
566                 lex.pushToken(token);
567         }
568         if (!lex.isOK())
569                 return;
570         lex.next();
571         token = lex.getString();
572         if (token == "height") {
573                 lex.next();
574                 height = LyXLength(lex.getString());
575         } else {
576                 lyxerr << "InsetBox::Read: Missing 'height'-tag!" << endl;
577                 lex.pushToken(token);
578         }
579         if (!lex.isOK())
580                 return;
581         lex.next();
582         token = lex.getString();
583         if (token == "height_special") {
584                 lex.next();
585                 height_special = lex.getString();
586         } else {
587                 lyxerr << "InsetBox::Read: Missing 'height_special'-tag!" << endl;
588                 lex.pushToken(token);
589         }
590 }