1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995-2000 the LyX Team.
8 * This file Copyright 2000 Baruch Even.
9 * ====================================================== */
12 How to use it for now:
13 * The lyxfunc 'graphics-insert' will insert this inset into the document.
18 * Add the GraphicsCache and FormatTranslator in order to get inline
19 viewing of the figures.
26 * If the image is from the clipart, and the document is moved to another
27 directory, the user is screwed. Need a way to handle it.
28 This amounts to a problem of when to use relative or absolute file paths
29 We should probably use what the user asks to use... but when he chooses
30 by the file dialog we normally get an absolute path and this may not be
32 * Bug in FileDlg class (src/filedlg.[hC]) when selecting a file and then
33 pressing ok, it counts as if no real selection done. Apparently it
34 when choosing a file it doesn't update the select file input line.
38 * How to support both PDF and PS output, should we do the conversion
39 or should we just give the bounding box and tell latex how to do the
41 I (Baruch Even) tend towards doing the conversion ourselves, otherwise
42 we need to give latex quite a few translation commands and from the
43 graphicx package docs it appears that it takes quite a bit of memory
44 on the side of TeXing.
48 * Add support for more features so that it will be useable as a drop in
49 replacement to insetfig.
50 * Keep aspect ratio radio button
52 * Create the GraphicsCache and FormatTranslator
53 * Add inline viewing of image.
55 TODO Before initial production release:
56 * Replace insetfig everywhere
57 * Read it's file format
58 * Get created by all commands used to create figinset currently.
59 * Search for comments of the form
60 // INSET_GRAPHICS: remove this when InsetFig is thrown.
63 * Pop up a dialog if the widget version is higher than what we accept.
64 * Finish the basic To-do list.
65 * Extract the general logic of the dialog in order to allow easier porting
66 to Gnome/KDE, and put the general logic in frontends and the inherited
67 platform dependent code in the appropriate dirs.
69 TODO Extended features:
71 * Advanced Latex tab folder.
72 * Add even more options to make it better than insetfig.
73 * Support for complete control over the latex parameters for TeXperts
74 * What advanced features the users want to do?
75 Implement them in a non latex dependent way, but a logical way.
76 LyX should translate it to latex or any other fitting format.
77 * Add a way to roll the image file into the file format.
78 * When loading if the image is not found in the expected place, try
79 to find it in the clipart, or in the same directory with the image.
80 * If the dialog had no real change from previous time, do not mark document
82 * Keep a tab on the image file, if it changes, update the lyx view.
88 * This is currently a moving target, I'm trying stuff and learning what
89 * is needed and how to accomplish it, since there is no predefined goal or
90 * way to go I invent it as I go.
92 * My current intention is for seperation from LaTeX, the basic needs are
93 * resizing and rotating, displaying on screen in various depths and printing
94 * conversion of depths (independent of the display depth). For this I'll
95 * provide a simple interface.
97 * The medium level includes clipping of the image, but in a limited way.
99 * For the LaTeX gurus I'll provide a complete control over the output, but
100 * this is latex dependent and guru dependent so I'd rather avoid doing this
101 * for the normal user. This stuff includes clipping, special image size
102 * specifications (\textwidth\minus 2in) which I see no way to generalize
103 * to non-latex specific way.
106 * 'graphicx' for the graphics inclusion.
107 * 'subfigure' for the subfigures.
111 * Current version is 1 (inset file format version), when changing it
112 * it should be changed in the Write() function when writing in one place
113 * and when reading one should change the version check and the error message.
115 * The filename is kept in the lyx file in a relative way, so as to allow
116 * moving the document file and its images with no problem.
120 * Apparently the PNG output is preferred over PDF images when doing PDF
121 * documents (i.e. prefer imagemagick eps2png over eps2pdf)
128 * Finish basic support:
129 * Inline image viewing
130 * Get into lyx-devel as an unactivated inset for the benefit of those
131 * who really need it.
133 * Do Release quality support:
134 * Allow to change display depth
135 * Make default figure instead of InsetFig
136 * Add to LyX (probably after 1.1.6 is released)
139 * Output format conversion
140 * Print depth changes
141 * Image file tracking of changes.
144 * Image roll-in (how? when? why?)
145 * This means to add the image inside the LyX file, usefull when
146 * transferring the file around.
150 #pragma implementation
155 #include "insets/insetgraphics.h"
156 #include "insets/insetgraphicsParams.h"
157 #include "graphics/GraphicsCache.h"
158 #include "graphics/GraphicsCacheItem.h"
160 #include "frontends/Dialogs.h"
163 #include "BufferView.h"
165 #include "lyx_gui_misc.h"
167 #include "support/FileInfo.h"
168 #include "support/filetools.h"
177 // Initialize only those variables that do not have a constructor.
178 InsetGraphics::InsetGraphics()
180 : use_bb(false), hiresbb(false), angle(0.0), origin(DEFAULT)
181 ,keepaspectratio(false), scale(0.0), clip(false), draft(false)
185 InsetGraphics::~InsetGraphics()
187 // Emits the hide signal to the dialog connected (if any)
191 int InsetGraphics::ascent(BufferView *, LyXFont const &) const
198 int InsetGraphics::descent(BufferView *, LyXFont const &) const
200 // this is not true if viewport is used and clip is not.
205 int InsetGraphics::width(BufferView *, LyXFont const &) const
207 // Need to replace this with data coming from GraphicsCache
210 return bb.urx - bb.llx + 2;
217 void InsetGraphics::draw(BufferView * bv, LyXFont const & font,
218 int baseline, float & x, bool) const
220 Painter & paint = bv->painter();
222 // This will draw the graphics. As for now we only draw a
223 // placeholder rectangele.
224 paint.rectangle(int(x)+2, baseline - ascent(bv, font),
226 ascent(bv, font) + descent(bv, font));
230 void InsetGraphics::Edit(BufferView *bv, int, int, unsigned int)
232 bv->owner()->getDialogs() -> showGraphics(this);
236 Inset::EDITABLE InsetGraphics::Editable() const
242 void InsetGraphics::Write(Buffer const * buf, ostream & os) const
244 os << "Graphics FormatVersion 1" << endl;
246 params.Write(buf, os);
250 // Baruch Even 2000-07-08
252 // A Thought for another way to read the file...
253 // The map should be a static part of the object or a static part of this
254 // file and should be filled during program start.
255 // The questions are:
256 // 1. Is this cleaner?
257 // 2. Is there no hidden performance costs?
259 // Regarding 2 I can already see that we will have two copies of the strings
260 // one in the data part of the program and one in the map, but that won't be
261 // more than say 2K (overestimation here), there is no real benefit to put
262 // it in the map since there aren't that many configuration items that will
263 // make it a faster solution, it might just be a bit cleaner.
264 // (a map stores either in a hash or a kind of a balanced tree).
266 void InsetGraphics::Read(Buffer const * buf, LyXLex & lex)
268 typedef map<string, enum TOKENS> ReadActionMap;
269 static ReadActionMap const readMap;
271 bool finished = false;
273 while (lex.IsOK() && !finished) {
276 string const token = lex.GetString();
277 lyxerr.debug() << "Token: '" << token << '\'' << endl;
282 ReadActionMap::const_iterator it =
285 if (it == readMap.end()) {
286 lyxerr << "Unknown keyword, skipping." << endl;
304 void InsetGraphics::Read(Buffer const * buf, LyXLex & lex)
306 bool finished = false;
308 while (lex.IsOK() && !finished) {
311 string const token = lex.GetString();
312 lyxerr.debug() << "Token: '" << token << '\'' << endl;
316 } else if (token == "\\end_inset") {
318 } else if (token == "FormatVersion") {
320 int version = lex.GetInteger();
323 << "This document was created with a newer Graphics widget"
324 ", You should use a newer version of LyX to read this"
327 // TODO: Possibly open up a dialog?
329 if (! params.Read(buf, lex, token))
330 lyxerr << "Unknown token, " << token << ",skipping." << endl;
337 static void formatResize(ostream & os, char const *key,
338 InsetGraphicsParams::Resize resizeType, double size)
340 switch (resizeType) {
341 case InsetGraphicsParams::DEFAULT_SIZE:
344 case InsetGraphicsParams::CM:
345 os << key << '=' << size << "cm,";
348 case InsetGraphicsParams::INCH:
349 os << key << '=' << size << "in,";
352 case InsetGraphicsParams::PERCENT_PAGE:
353 os << key << '=' << size/100 << "\\text" << key << ',';
356 case InsetGraphicsParams::PERCENT_COLUMN:
357 os << key << '=' << size/100 << "\\column" << key << ',';
363 int InsetGraphics::Latex(Buffer const *buf, ostream & os,
364 bool /*fragile*/, bool/*fs*/) const
366 // MISSING: We have to decide how to do the order of the options
367 // that is dependent of order, like witdth, height, angle. Should
368 // we rotate before scale? Should we let the user decide?
369 // bool rot_before_scale; ?
371 // (BE) As a first step we should do a scale before rotate since this is
372 // more like the natural thought of how to do it.
373 // (BE) I believe that a priority list presented to the user with
374 // a default order would be the best, though it would be better to
375 // hide such a thing in an "Advanced options" dialog.
376 // (BE) This should go an advanced LaTeX options dialog.
378 // If there is no file specified, just output a message about it in
380 if (params.filename.empty()) {
381 os << "\\fbox{\\rule[-0.5in]{0pt}{1in}"
382 << _("empty figure path")
389 // Calculate the options part of the command, we must do it to a string
390 // stream since we might have a trailing comma that we would like to remove
391 // before writing it to the output stream.
393 std::ostringstream options;
398 formatResize(options, "width", params.widthResize, params.widthSize);
399 formatResize(options, "height", params.heightResize, params.heightSize);
401 if (params.rotateAngle != 0) {
403 << params.rotateAngle << ',';
407 if (bb.isSet() && use_bb) {
409 << bb.llx << ' ' << bb.lly << ' '
410 << bb.urx << ' ' << bb.ury << ',';
413 options << "hiresbb,";
415 if (viewport.isSet()) {
416 options << "viewport="
417 << viewport.llx << ' ' << viewport.lly << ' '
418 << viewport.urx << ' ' << viewport.ury << ',';
422 << trim.llx << ' ' << trim.lly << ' '
423 << trim.urx << ' ' << trim.ury << ',';
425 if (natheight.value() != 0) {
426 options << "natheight=" << natheight.asString() << ',';
428 if (natwidth.value() != 0) {
429 options << "natwidth=" << natwidth.asString() << ',';
432 options << "angle=" << angle << ',';
434 if (origin != DEFAULT) {
438 options << "origin=lt,";
441 options << "origin=lc,";
444 options << "origin=lB,";
447 options << "origin=lb,";
450 options << "origin=ct,";
453 options << "origin=c,";
456 options << "origin=cB,";
459 options << "origin=cb,";
462 options << "origin=rt,";
465 options << "origin=rc,";
468 options << "origin=rB,";
471 options << "origin=rb,";
475 if (g_width.value() != 0) {
476 options << "width=" << g_width.asString() << ',';
478 if (g_height.value() != 0) {
479 options << "height=" << g_height.asString() << ',';
481 if (totalheight.value() != 0) {
482 options << "totalheight=" << totalheight.asString() << ',';
484 if (keepaspectratio) {
485 options << "keepaspectratio,";
488 options << "scale=" << scale << ',';
497 options << "type=" << type << ',';
499 // These should be present only when type is used.
501 options << "ext=" << type << ',';
504 options << "read=" << type << ',';
506 if (!command.empty()) {
507 options << "command=" << type << ',';
513 string opts(options.str().c_str());
516 char * tmp = options.str();
520 opts = strip(opts, ',');
523 // If it's not an inline image, surround it with the centering paragraph.
524 if (! params.inlineFigure) {
526 << "\\vspace{0.3cm}" << endl
527 << "{\\par\\centering ";
530 // Do we want subcaptions?
531 if (params.subcaption) {
532 os << "\\subfigure[" << params.subcaptionText << "]{";
535 // We never used the starred form, we use the "clip" option instead.
536 os << "\\includegraphics";
539 os << '[' << opts << ']';
542 // Make the filename relative to the lyx file
543 string filename = MakeRelPath(params.filename, OnlyPath(buf->fileName()));
545 // and remove the extension so the LaTeX will use whatever is
546 // appropriate (when there are several versions in different formats)
547 filename = ChangeExtension(filename, string());
549 os << '{' << filename << '}';
551 // Do we want a subcaption?
552 if (params.subcaption) {
553 // Close the subcaption command
557 // Is this an inline graphics?
558 if (!params.inlineFigure) {
559 os << " \\par}" << endl
560 << "\\vspace{0.3cm}" << endl;
563 // How do we decide to what format should we export?
564 // cachehandle->export(ImageType::EPS);
565 // cachehandle->export(ImageType::PNG);
571 int InsetGraphics::Ascii(Buffer const *, ostream &) const
573 // No graphics in ascii output.
578 int InsetGraphics::Linuxdoc(Buffer const *, ostream &) const
580 // No graphics in LinuxDoc output. Should check how/what to add.
585 int InsetGraphics::DocBook(Buffer const *, ostream &) const
587 // No graphics in DocBook output. Should check how/what to add.
592 void InsetGraphics::Validate(LaTeXFeatures & features) const
594 // If we have no image, we should not require anything.
595 if (params.filename.empty())
598 features.graphicx = true;
600 if (params.subcaption)
601 features.subfigure = true;
604 // Update the inset after parameters changed (read from file or changed in
606 void InsetGraphics::updateInset()
608 // If file changed...
609 //graphicscache.addFile(params.filename);
610 //bb = graphicscache.getBB(params.filename);
611 //pixmap = graphicscache.getPixmap(params.filename);
614 bool InsetGraphics::setParams(InsetGraphicsParams const & params)
616 // TODO: Make it return true only when the data has been changed.
617 // for this to work we still need to implement operator == in
618 // InsetGraphicsParams
619 if (this->params == params)
622 // Copy the new parameters.
623 this->params = params;
625 // Update the inset with the new parameters.
628 // We have changed data, report it.
632 InsetGraphicsParams InsetGraphics::getParams() const
637 Inset * InsetGraphics::Clone() const
639 InsetGraphics * newInset = new InsetGraphics;
640 newInset->setParams(getParams());