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.
46 * How do we handle the inline viewing? we may need to show the same image
47 in several formats (color, monochrome, grayscale) or even in different
48 sizes, not to mention rotations!
52 * Add support for more features so that it will be better than insetfig.
53 * Keep aspect ratio radio button
55 * Create the GraphicsCache and FormatTranslator
56 * Add inline viewing of image.
58 TODO Before initial production release:
59 * Replace insetfig everywhere
60 * Read it's file format
61 * Get created by all commands used to create figinset currently.
62 * Search for comments of the form
63 // INSET_GRAPHICS: remove this when InsetFig is thrown.
66 * Pop up a dialog if the widget version is higher than what we accept.
67 * Finish the basic To-do list.
68 * Extract the general logic of the dialog in order to allow easier porting
69 to Gnome/KDE, and put the general logic in frontends and the inherited
70 platform dependent code in the appropriate dirs.
72 TODO Extended features:
74 * Advanced Latex tab folder.
75 * Add even more options to make it better than insetfig.
76 * Support for complete control over the latex parameters for TeXperts
77 * What advanced features the users want to do?
78 Implement them in a non latex dependent way, but a logical way.
79 LyX should translate it to latex or any other fitting format.
80 * Add a way to roll the image file into the file format.
81 * When loading if the image is not found in the expected place, try
82 to find it in the clipart, or in the same directory with the image.
83 * If the dialog had no real change from previous time, do not mark document
85 * Keep a tab on the image file, if it changes, update the lyx view.
86 * The image choosing dialog could show thumbnails of the image formats
87 it knows of, thus selection based on the image instead of based on
94 * This is currently a moving target, I'm trying stuff and learning what
95 * is needed and how to accomplish it, since there is no predefined goal or
96 * way to go I invent it as I go.
98 * My current intention is for seperation from LaTeX, the basic needs are
99 * resizing and rotating, displaying on screen in various depths and printing
100 * conversion of depths (independent of the display depth). For this I'll
101 * provide a simple interface.
103 * The medium level includes clipping of the image, but in a limited way.
105 * For the LaTeX gurus I'll provide a complete control over the output, but
106 * this is latex dependent and guru dependent so I'd rather avoid doing this
107 * for the normal user. This stuff includes clipping, special image size
108 * specifications (\textwidth\minus 2in) which I see no way to generalize
109 * to non-latex specific way.
112 * 'graphicx' for the graphics inclusion.
113 * 'subfigure' for the subfigures.
117 * Current version is 1 (inset file format version), when changing it
118 * it should be changed in the Write() function when writing in one place
119 * and when reading one should change the version check and the error message.
121 * The filename is kept in the lyx file in a relative way, so as to allow
122 * moving the document file and its images with no problem.
126 * Apparently the PNG output is preferred over PDF images when doing PDF
127 * documents (i.e. prefer imagemagick eps2png over eps2pdf)
134 * Finish basic support:
135 * Inline image viewing
136 * Get into lyx-devel as an unactivated inset for the benefit of those
137 * who really need it.
139 * Do Release quality support:
140 * Allow to change display depth
141 * Make default figure instead of InsetFig
142 * Add to LyX (probably after 1.1.6 is released)
145 * Output format conversion
146 * Print depth changes
147 * Image file tracking of changes.
150 * Image roll-in (how? when? why?)
151 * This means to add the image inside the LyX file, usefull when
152 * transferring the file around.
157 #pragma implementation
162 #include "insets/insetgraphics.h"
163 #include "insets/insetgraphicsParams.h"
164 #include "graphics/GraphicsCache.h"
165 #include "graphics/GraphicsCacheItem.h"
167 #include "frontends/Dialogs.h"
170 #include "BufferView.h"
172 #include "lyx_gui_misc.h"
174 #include "support/FileInfo.h"
175 #include "support/filetools.h"
184 // Initialize only those variables that do not have a constructor.
185 InsetGraphics::InsetGraphics()
187 : use_bb(false), hiresbb(false), angle(0.0), origin(DEFAULT)
188 ,keepaspectratio(false), scale(0.0), clip(false), draft(false)
190 : cachehandle(0), bv_(0)
193 InsetGraphics::~InsetGraphics()
195 // Emits the hide signal to the dialog connected (if any)
199 int InsetGraphics::ascent(BufferView *, LyXFont const &) const
202 cachehandle->getImageStatus() == GraphicsCacheItem::Loaded)
203 return cachehandle->getHeight();
209 int InsetGraphics::descent(BufferView *, LyXFont const &) const
211 // this is not true if viewport is used and clip is not.
216 int InsetGraphics::width(BufferView *, LyXFont const &) const
219 cachehandle->getImageStatus() == GraphicsCacheItem::Loaded)
220 return cachehandle->getWidth();
226 void InsetGraphics::draw(BufferView * bv, LyXFont const & font,
227 int baseline, float & x, bool) const
229 Painter & paint = bv->painter();
232 // This will draw the graphics. As for now we only draw a
233 // placeholder rectangele.
235 cachehandle->getImageStatus() == GraphicsCacheItem::Loaded) {
237 paint.pixmap(int(x)+2, baseline - ascent(bv, font),
239 ascent(bv,font) + descent(bv,font),
240 cachehandle->getImage());
242 paint.rectangle(int(x)+2, baseline - ascent(bv, font),
244 ascent(bv, font) + descent(bv, font));
248 x += width(bv, font);
252 void InsetGraphics::Edit(BufferView *bv, int, int, unsigned int)
255 bv->owner()->getDialogs() -> showGraphics(this);
259 Inset::EDITABLE InsetGraphics::Editable() const
265 void InsetGraphics::Write(Buffer const * buf, ostream & os) const
267 os << "GRAPHICS FormatVersion 1" << endl;
269 params.Write(buf, os);
273 // Baruch Even 2000-07-08
275 // A Thought for another way to read the file...
276 // The map should be a static part of the object or a static part of this
277 // file and should be filled during program start.
278 // The questions are:
279 // 1. Is this cleaner?
280 // 2. Is there no hidden performance costs?
282 // Regarding 2 I can already see that we will have two copies of the strings
283 // one in the data part of the program and one in the map, but that won't be
284 // more than say 2K (overestimation here), there is no real benefit to put
285 // it in the map since there aren't that many configuration items that will
286 // make it a faster solution, it might just be a bit cleaner.
287 // (a map stores either in a hash or a kind of a balanced tree).
289 void InsetGraphics::Read(Buffer const * buf, LyXLex & lex)
291 typedef map<string, enum TOKENS> ReadActionMap;
292 static ReadActionMap const readMap;
294 bool finished = false;
296 while (lex.IsOK() && !finished) {
299 string const token = lex.GetString();
300 lyxerr.debug() << "Token: '" << token << '\'' << endl;
305 ReadActionMap::const_iterator it =
308 if (it == readMap.end()) {
309 lyxerr << "Unknown keyword, skipping." << endl;
327 void InsetGraphics::Read(Buffer const * buf, LyXLex & lex)
329 bool finished = false;
331 while (lex.IsOK() && !finished) {
334 string const token = lex.GetString();
335 lyxerr.debug() << "Token: '" << token << '\'' << endl;
339 } else if (token == "\\end_inset") {
341 } else if (token == "FormatVersion") {
343 int version = lex.GetInteger();
346 << "This document was created with a newer Graphics widget"
347 ", You should use a newer version of LyX to read this"
350 // TODO: Possibly open up a dialog?
352 if (! params.Read(buf, lex, token))
353 lyxerr << "Unknown token, " << token << ",skipping." << endl;
360 static void formatResize(ostream & os, char const *key,
361 InsetGraphicsParams::Resize resizeType, double size)
363 switch (resizeType) {
364 case InsetGraphicsParams::DEFAULT_SIZE:
367 case InsetGraphicsParams::CM:
368 os << key << '=' << size << "cm,";
371 case InsetGraphicsParams::INCH:
372 os << key << '=' << size << "in,";
375 case InsetGraphicsParams::PERCENT_PAGE:
376 os << key << '=' << size/100 << "\\text" << key << ',';
379 case InsetGraphicsParams::PERCENT_COLUMN:
380 os << key << '=' << size/100 << "\\column" << key << ',';
386 int InsetGraphics::Latex(Buffer const *buf, ostream & os,
387 bool /*fragile*/, bool/*fs*/) const
389 // MISSING: We have to decide how to do the order of the options
390 // that is dependent of order, like witdth, height, angle. Should
391 // we rotate before scale? Should we let the user decide?
392 // bool rot_before_scale; ?
394 // (BE) As a first step we should do a scale before rotate since this is
395 // more like the natural thought of how to do it.
396 // (BE) I believe that a priority list presented to the user with
397 // a default order would be the best, though it would be better to
398 // hide such a thing in an "Advanced options" dialog.
399 // (BE) This should go an advanced LaTeX options dialog.
401 // If there is no file specified, just output a message about it in
403 if (params.filename.empty()) {
404 os << "\\fbox{\\rule[-0.5in]{0pt}{1in}"
405 << _("empty figure path")
412 // Calculate the options part of the command, we must do it to a string
413 // stream since we might have a trailing comma that we would like to remove
414 // before writing it to the output stream.
416 std::ostringstream options;
421 formatResize(options, "width", params.widthResize, params.widthSize);
422 formatResize(options, "height", params.heightResize, params.heightSize);
424 if (params.rotateAngle != 0) {
426 << params.rotateAngle << ',';
430 if (bb.isSet() && use_bb) {
432 << bb.llx << ' ' << bb.lly << ' '
433 << bb.urx << ' ' << bb.ury << ',';
436 options << "hiresbb,";
438 if (viewport.isSet()) {
439 options << "viewport="
440 << viewport.llx << ' ' << viewport.lly << ' '
441 << viewport.urx << ' ' << viewport.ury << ',';
445 << trim.llx << ' ' << trim.lly << ' '
446 << trim.urx << ' ' << trim.ury << ',';
448 if (natheight.value() != 0) {
449 options << "natheight=" << natheight.asString() << ',';
451 if (natwidth.value() != 0) {
452 options << "natwidth=" << natwidth.asString() << ',';
455 options << "angle=" << angle << ',';
457 if (origin != DEFAULT) {
461 options << "origin=lt,";
464 options << "origin=lc,";
467 options << "origin=lB,";
470 options << "origin=lb,";
473 options << "origin=ct,";
476 options << "origin=c,";
479 options << "origin=cB,";
482 options << "origin=cb,";
485 options << "origin=rt,";
488 options << "origin=rc,";
491 options << "origin=rB,";
494 options << "origin=rb,";
498 if (g_width.value() != 0) {
499 options << "width=" << g_width.asString() << ',';
501 if (g_height.value() != 0) {
502 options << "height=" << g_height.asString() << ',';
504 if (totalheight.value() != 0) {
505 options << "totalheight=" << totalheight.asString() << ',';
507 if (keepaspectratio) {
508 options << "keepaspectratio,";
511 options << "scale=" << scale << ',';
520 options << "type=" << type << ',';
522 // These should be present only when type is used.
524 options << "ext=" << type << ',';
527 options << "read=" << type << ',';
529 if (!command.empty()) {
530 options << "command=" << type << ',';
536 string opts(options.str().c_str());
539 char * tmp = options.str();
543 opts = strip(opts, ',');
546 // If it's not an inline image, surround it with the centering paragraph.
547 if (! params.inlineFigure) {
549 << "\\vspace{0.3cm}" << endl
550 << "{\\par\\centering ";
553 // Do we want subcaptions?
554 if (params.subcaption) {
555 os << "\\subfigure[" << params.subcaptionText << "]{";
558 // We never used the starred form, we use the "clip" option instead.
559 os << "\\includegraphics";
562 os << '[' << opts << ']';
565 // Make the filename relative to the lyx file
566 string filename = MakeRelPath(params.filename, OnlyPath(buf->fileName()));
568 // and remove the extension so the LaTeX will use whatever is
569 // appropriate (when there are several versions in different formats)
570 filename = ChangeExtension(filename, string());
572 os << '{' << filename << '}';
574 // Do we want a subcaption?
575 if (params.subcaption) {
576 // Close the subcaption command
580 // Is this an inline graphics?
581 if (!params.inlineFigure) {
582 os << " \\par}" << endl
583 << "\\vspace{0.3cm}" << endl;
586 // How do we decide to what format should we export?
587 // cachehandle->export(ImageType::EPS);
588 // cachehandle->export(ImageType::PNG);
594 int InsetGraphics::Ascii(Buffer const *, ostream &) const
596 // No graphics in ascii output.
601 int InsetGraphics::Linuxdoc(Buffer const *, ostream &) const
603 // No graphics in LinuxDoc output. Should check how/what to add.
608 int InsetGraphics::DocBook(Buffer const *, ostream &) const
610 // No graphics in DocBook output. Should check how/what to add.
615 void InsetGraphics::Validate(LaTeXFeatures & features) const
617 // If we have no image, we should not require anything.
618 if (params.filename.empty())
621 features.graphicx = true;
623 if (params.subcaption)
624 features.subfigure = true;
627 // Update the inset after parameters changed (read from file or changed in
629 void InsetGraphics::updateInset()
631 // If file changed...
633 GraphicsCache * gc = GraphicsCache::getInstance();
634 GraphicsCacheItem * temp = 0;
636 if (!params.filename.empty()) {
637 temp = gc->addFile(params.filename);
639 temp->imageDone.connect(slot(this, &InsetGraphics::imageDone));
647 void InsetGraphics::imageDone()
650 bv_->updateInset(this, false);
653 bool InsetGraphics::setParams(InsetGraphicsParams const & params)
655 // If nothing is changed, just return and say so.
656 if (this->params == params)
659 // Copy the new parameters.
660 this->params = params;
662 // Update the inset with the new parameters.
665 // We have changed data, report it.
669 InsetGraphicsParams InsetGraphics::getParams() const
674 Inset * InsetGraphics::Clone() const
676 InsetGraphics * newInset = new InsetGraphics;
677 newInset->setParams(getParams());