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"
185 // Initialize only those variables that do not have a constructor.
186 InsetGraphics::InsetGraphics()
188 : use_bb(false), hiresbb(false), angle(0.0), origin(DEFAULT)
189 ,keepaspectratio(false), scale(0.0), clip(false), draft(false)
192 : cacheHandle(0), pixmapInitialized(false)
195 InsetGraphics::~InsetGraphics()
197 // Emits the hide signal to the dialog connected (if any)
201 int InsetGraphics::ascent(BufferView *, LyXFont const &) const
203 if (pixmapInitialized)
204 return cacheHandle->getHeight();
210 int InsetGraphics::descent(BufferView *, LyXFont const &) const
212 // this is not true if viewport is used and clip is not.
217 int InsetGraphics::width(BufferView *, LyXFont const &) const
219 if (pixmapInitialized)
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();
231 // This will draw the graphics. If the graphics has not been loaded yet,
232 // we draw just a rectangle.
233 if (pixmapInitialized) {
235 paint.pixmap(int(x)+2, baseline - ascent(bv, font),
237 ascent(bv,font) + descent(bv,font),
240 paint.rectangle(int(x)+2, baseline - ascent(bv, font),
242 ascent(bv, font) + descent(bv, font));
244 // Check if the image is now ready.
246 (cacheHandle->getImageStatus() == GraphicsCacheItem::Loaded)) {
247 pixmap = cacheHandle->getImage();
248 pixmapInitialized = true;
250 // Tell BufferView we need to be updated!
251 bv->text->status = LyXText::CHANGED_IN_DRAW;
255 x += width(bv, font);
259 void InsetGraphics::Edit(BufferView *bv, int, int, unsigned int)
261 bv->owner()->getDialogs() -> showGraphics(this);
265 Inset::EDITABLE InsetGraphics::Editable() const
271 void InsetGraphics::Write(Buffer const * buf, ostream & os) const
273 os << "GRAPHICS FormatVersion 1" << endl;
275 params.Write(buf, os);
279 // Baruch Even 2000-07-08
281 // A Thought for another way to read the file...
282 // The map should be a static part of the object or a static part of this
283 // file and should be filled during program start.
284 // The questions are:
285 // 1. Is this cleaner?
286 // 2. Is there no hidden performance costs?
288 // Regarding 2 I can already see that we will have two copies of the strings
289 // one in the data part of the program and one in the map, but that won't be
290 // more than say 2K (overestimation here), there is no real benefit to put
291 // it in the map since there aren't that many configuration items that will
292 // make it a faster solution, it might just be a bit cleaner.
293 // (a map stores either in a hash or a kind of a balanced tree).
295 void InsetGraphics::Read(Buffer const * buf, LyXLex & lex)
297 typedef map<string, enum TOKENS> ReadActionMap;
298 static ReadActionMap const readMap;
300 bool finished = false;
302 while (lex.IsOK() && !finished) {
305 string const token = lex.GetString();
306 lyxerr.debug() << "Token: '" << token << '\'' << endl;
311 ReadActionMap::const_iterator it =
314 if (it == readMap.end()) {
315 lyxerr << "Unknown keyword, skipping." << endl;
333 void InsetGraphics::Read(Buffer const * buf, LyXLex & lex)
335 bool finished = false;
337 while (lex.IsOK() && !finished) {
340 string const token = lex.GetString();
341 lyxerr.debug() << "Token: '" << token << '\'' << endl;
345 } else if (token == "\\end_inset") {
347 } else if (token == "FormatVersion") {
349 int version = lex.GetInteger();
352 << "This document was created with a newer Graphics widget"
353 ", You should use a newer version of LyX to read this"
356 // TODO: Possibly open up a dialog?
358 if (! params.Read(buf, lex, token))
359 lyxerr << "Unknown token, " << token << ",skipping." << endl;
366 static void formatResize(ostream & os, char const *key,
367 InsetGraphicsParams::Resize resizeType, double size)
369 switch (resizeType) {
370 case InsetGraphicsParams::DEFAULT_SIZE:
373 case InsetGraphicsParams::CM:
374 os << key << '=' << size << "cm,";
377 case InsetGraphicsParams::INCH:
378 os << key << '=' << size << "in,";
381 case InsetGraphicsParams::PERCENT_PAGE:
382 os << key << '=' << size/100 << "\\text" << key << ',';
385 case InsetGraphicsParams::PERCENT_COLUMN:
386 os << key << '=' << size/100 << "\\column" << key << ',';
392 int InsetGraphics::Latex(Buffer const *buf, ostream & os,
393 bool /*fragile*/, bool/*fs*/) const
395 // MISSING: We have to decide how to do the order of the options
396 // that is dependent of order, like witdth, height, angle. Should
397 // we rotate before scale? Should we let the user decide?
398 // bool rot_before_scale; ?
400 // (BE) As a first step we should do a scale before rotate since this is
401 // more like the natural thought of how to do it.
402 // (BE) I believe that a priority list presented to the user with
403 // a default order would be the best, though it would be better to
404 // hide such a thing in an "Advanced options" dialog.
405 // (BE) This should go an advanced LaTeX options dialog.
407 // If there is no file specified, just output a message about it in
409 if (params.filename.empty()) {
410 os << "\\fbox{\\rule[-0.5in]{0pt}{1in}"
411 << _("empty figure path")
418 // Calculate the options part of the command, we must do it to a string
419 // stream since we might have a trailing comma that we would like to remove
420 // before writing it to the output stream.
422 std::ostringstream options;
427 formatResize(options, "width", params.widthResize, params.widthSize);
428 formatResize(options, "height", params.heightResize, params.heightSize);
430 if (params.rotateAngle != 0) {
432 << params.rotateAngle << ',';
436 if (bb.isSet() && use_bb) {
438 << bb.llx << ' ' << bb.lly << ' '
439 << bb.urx << ' ' << bb.ury << ',';
442 options << "hiresbb,";
444 if (viewport.isSet()) {
445 options << "viewport="
446 << viewport.llx << ' ' << viewport.lly << ' '
447 << viewport.urx << ' ' << viewport.ury << ',';
451 << trim.llx << ' ' << trim.lly << ' '
452 << trim.urx << ' ' << trim.ury << ',';
454 if (natheight.value() != 0) {
455 options << "natheight=" << natheight.asString() << ',';
457 if (natwidth.value() != 0) {
458 options << "natwidth=" << natwidth.asString() << ',';
461 options << "angle=" << angle << ',';
463 if (origin != DEFAULT) {
467 options << "origin=lt,";
470 options << "origin=lc,";
473 options << "origin=lB,";
476 options << "origin=lb,";
479 options << "origin=ct,";
482 options << "origin=c,";
485 options << "origin=cB,";
488 options << "origin=cb,";
491 options << "origin=rt,";
494 options << "origin=rc,";
497 options << "origin=rB,";
500 options << "origin=rb,";
504 if (g_width.value() != 0) {
505 options << "width=" << g_width.asString() << ',';
507 if (g_height.value() != 0) {
508 options << "height=" << g_height.asString() << ',';
510 if (totalheight.value() != 0) {
511 options << "totalheight=" << totalheight.asString() << ',';
513 if (keepaspectratio) {
514 options << "keepaspectratio,";
517 options << "scale=" << scale << ',';
526 options << "type=" << type << ',';
528 // These should be present only when type is used.
530 options << "ext=" << type << ',';
533 options << "read=" << type << ',';
535 if (!command.empty()) {
536 options << "command=" << type << ',';
542 string opts(options.str().c_str());
545 char * tmp = options.str();
549 opts = strip(opts, ',');
552 // If it's not an inline image, surround it with the centering paragraph.
553 if (! params.inlineFigure) {
555 << "\\vspace{0.3cm}" << endl
556 << "{\\par\\centering ";
559 // Do we want subcaptions?
560 if (params.subcaption) {
561 os << "\\subfigure[" << params.subcaptionText << "]{";
564 // We never used the starred form, we use the "clip" option instead.
565 os << "\\includegraphics";
568 os << '[' << opts << ']';
571 // Make the filename relative to the lyx file
572 string filename = MakeRelPath(params.filename, OnlyPath(buf->fileName()));
574 // and remove the extension so the LaTeX will use whatever is
575 // appropriate (when there are several versions in different formats)
576 filename = ChangeExtension(filename, string());
578 os << '{' << filename << '}';
580 // Do we want a subcaption?
581 if (params.subcaption) {
582 // Close the subcaption command
586 // Is this an inline graphics?
587 if (!params.inlineFigure) {
588 os << " \\par}" << endl
589 << "\\vspace{0.3cm}" << endl;
592 // How do we decide to what format should we export?
593 // cacheHandle->>export(ImageType::EPS);
594 // cacheHandle->>export(ImageType::PNG);
600 int InsetGraphics::Ascii(Buffer const *, ostream &) const
602 // No graphics in ascii output.
607 int InsetGraphics::Linuxdoc(Buffer const *, ostream &) const
609 // No graphics in LinuxDoc output. Should check how/what to add.
614 int InsetGraphics::DocBook(Buffer const *, ostream &) const
616 // No graphics in DocBook output. Should check how/what to add.
621 void InsetGraphics::Validate(LaTeXFeatures & features) const
623 // If we have no image, we should not require anything.
624 if (params.filename.empty())
627 features.graphicx = true;
629 if (params.subcaption)
630 features.subfigure = true;
633 // Update the inset after parameters changed (read from file or changed in
635 void InsetGraphics::updateInset()
637 // If file changed...
639 GraphicsCache * gc = GraphicsCache::getInstance();
640 GraphicsCacheItem * temp = 0;
642 if (!params.filename.empty()) {
643 temp = gc->addFile(params.filename);
650 bool InsetGraphics::setParams(InsetGraphicsParams const & params)
652 // If nothing is changed, just return and say so.
653 if (this->params == params)
656 // Copy the new parameters.
657 this->params = params;
659 // Update the inset with the new parameters.
662 // We have changed data, report it.
666 InsetGraphicsParams InsetGraphics::getParams() const
671 Inset * InsetGraphics::Clone() const
673 InsetGraphics * newInset = new InsetGraphics;
674 newInset->setParams(getParams());