+2000-08-07 Baruch Even <baruch.even@writeme.com>
+
+ * src/graphics/Renderer.h:
+ * src/graphics/Renderer.C: Added base class for rendering of different
+ image formats into Pixmaps.
+
+ * src/graphics/XPM_Renderer.h:
+ * src/graphics/XPM_Renderer.C: Taken from GraphicsCacheItem and placed
+ in a different class.
+
+ * src/graphics/GraphicsCacheItem.C: factored out the rendering in order to
+ easily add support for other formats.
+
+ * src/insets/figinset.C: plugged a leak of an X resource.
+
2000-08-07 Lars Gullik Bjønnes <larsbj@lyx.org>
* src/CutAndPaste.[Ch]: make all metods static.
* src/tabular.C (UseParbox): new function
+2000-08-06 Baruch Even <baruch.even@writeme.com>
+
+ * src/graphics/GraphicsCache.h:
+ * src/graphics/GraphicsCache.C:
+ * src/graphics/GraphicsCacheItem.h:
+ * src/graphics/GraphicsCacheItem.C: Made them to actually do something
+ usefull.
+
+ * src/insets/insetgraphics.h:
+ * src/insets/insetgraphics.C: Added the use of the GraphicsCache and the
+ drawing of the inline image.
+
+ * src/buffer.C: Fixed a bug where a loaded InsetGraphics would be loaded
+ into the wrong position.
+
+ * src/lyxfunc.C: When adding an InsetGraphics the edit dialog is now
+ launched.
+
2000-08-05 Lars Gullik Bjønnes <larsbj@lyx.org>
* src/support/translator.h: move all typedefs to public section
} else if (tmptok == "GRAPHICS") {
Inset * inset = new InsetGraphics;
inset->Read(this, lex);
- ++pos;
par->InsertInset(pos, inset, font);
+ ++pos;
} else if (tmptok == "LatexCommand") {
InsetCommandParams inscmd;
inscmd.Read(lex);
#endif
#include <config.h>
+
#include "lyx_gui_misc.h"
#include "gettext.h"
#include FORMS_H_LOCATION
FormGraphics * pre = static_cast<FormGraphics*>(ob->form->u_vdata);
pre->input();
}
+
#define FORMGRAPHICS_H
#include <config.h>
+
#include "LString.h"
#include "frontends/DialogBase.h"
//#include "form_graphics.h"
};
#endif
-
-
// File modified by fdfix.sh for use by lyx (with xforms >= 0.88) and gettext
#include <config.h>
+
#include "lyx_gui_misc.h"
#include "gettext.h"
return fdui;
}
/*---------------------------------------*/
-
#include "GraphicsCache.h"
+#include "support/LAssert.h"
GraphicsCache * GraphicsCache::singleton = 0;
{
if (! singleton) {
singleton = new GraphicsCache;
+ Assert(singleton != 0);
}
return singleton;
GraphicsCache::~GraphicsCache()
{
- delete singleton;
+ // Free the map.
+ //std::foreach(map.begin(), map.end(), ...);
+ // This is not really needed, it will only happen on program close and in
+ // any case the OS will release those resources (not doing it may have
+ // a good effect on closing time).
+
+ delete singleton;
}
if (it != cache.end()) {
return (*it).second;
}
- // INCOMPLETE!
- return 0;
+
+ GraphicsCacheItem * cacheItem = new GraphicsCacheItem();
+ if (cacheItem == 0) {
+ return 0;
+ }
+
+ bool result = cacheItem->setFilename(filename);
+ if (!result)
+ return 0;
+
+ cache[filename] = cacheItem;
+
+ return cacheItem;
}
typedef std::map<string, GraphicsCacheItem *> CacheType;
///
CacheType cache;
+
+ // We need this so that an Item can tell the cache that it should be
+ // deleted. (to call removeFile).
+ // It also helps removing a warning gcc emits.
+ friend GraphicsCacheItem;
};
#endif
#include "GraphicsCacheItem.h"
+#include "graphics/XPM_Renderer.h"
+#include "support/filetools.h"
+#include "debug.h"
+#include "support/LAssert.h"
+#include <unistd.h> // unlink
+
+#include <map>
+
+#include FORMS_H_LOCATION
+
+using std::endl;
+
+GraphicsCacheItem::GraphicsCacheItem()
+ : height_(-1), width_(-1), imageStatus_(Loading),
+ pixmap_(0), renderer(0)
+{}
+
+GraphicsCacheItem::~GraphicsCacheItem()
+{
+ if (imageStatus_ == Loaded) {
+ XFreePixmap(fl_display, pixmap_);
+ }
+
+ delete renderer;
+}
+
+bool
+GraphicsCacheItem::setFilename(string const & filename)
+{
+ imageStatus_ = Loading;
+
+ renderer = new XPM_Renderer();
+ if (renderXPM(filename))
+ return true;
+
+ return false;
+}
+
+/*** Callback method ***/
+
+typedef map<string, GraphicsCacheItem*> CallbackMap;
+static CallbackMap callbackMap;
+
+void
+callback(string cmd, int retval)
+{
+ lyxerr << "callback, cmd="<<cmd<<", retval="<<retval<<endl;
+
+ GraphicsCacheItem * item = callbackMap[cmd];
+ callbackMap.erase(cmd);
+
+ item->imageConverted(retval);
+}
+
+void
+GraphicsCacheItem::imageConverted(int retval)
+{
+ lyxerr << "imageConverted, retval="<<retval<<endl;
+
+ if (retval) {
+ imageStatus_ = ErrorConverting;
+ return;
+ }
+
+ // Do the actual image loading from XPM to memory.
+ loadXPMImage();
+}
+
+/**********************/
+
+bool
+GraphicsCacheItem::renderXPM(string const & filename)
+{
+ // Create the command to do the conversion, this depends on ImageMagicks
+ // convert program.
+ string command = "convert ";
+ command += filename;
+ command += " XPM:";
+
+ // Take only the filename part of the file, without path or extension.
+ string temp = OnlyFilename(filename);
+ temp = ChangeExtension(filename , string());
+
+ // Add some stuff to have it a unique temp file.
+ xpmfile = TmpFileName(string(), temp);
+ xpmfile = ChangeExtension(xpmfile, ".xpm");
+
+ command += xpmfile;
+
+ // Set the callback mapping to point to us.
+ callbackMap[command] = this;
+
+ // Run the convertor.
+ // There is a problem with running it asyncronously, it doesn't return
+ // to call the callback, so until the Systemcalls mechanism is fixed
+ // I use the syncronous method.
+ lyxerr << "Launching convert to xpm, command="<<command<<endl;
+// syscall.startscript(Systemcalls::DontWait, command, &callback);
+ syscall.startscript(Systemcalls::Wait, command, &callback);
+
+ return true;
+}
+
+// This function gets called from the callback after the image has been
+// converted successfully.
+void
+GraphicsCacheItem::loadXPMImage()
+{
+ if (! renderer->setFilename(xpmfile)) {
+ return;
+ }
+
+ if (renderer->renderImage()) {
+ pixmap_ = renderer->getPixmap();
+ width_ = renderer->getWidth();
+ height_ = renderer->getHeight();
+ imageStatus_ = Loaded;
+ } else {
+ imageStatus_ = ErrorReading;
+ }
+
+ imageDone.emit();
+
+ // remove the xpm file now.
+ ::unlink(xpmfile.c_str());
+ // and remove the reference to the filename.
+ xpmfile = string();
+}
#ifndef GRAPHICSCACHEITEM_H
#define GRAPHICSCACHEITEM_H
+#include <config.h>
+
#ifdef __GNUG__
#pragma interface
#endif
-///
+#include XPM_H_LOCATION
+#include "LString.h"
+#include "graphics/Renderer.h"
+#include "support/syscall.h"
+
+#include "sigc++/signal_system.h"
+#ifdef SIGC_CXX_NAMESPACES
+using SigC::Signal0;
+#endif
+
+/* (Baruch Even 2000-08-05)
+ * This has a major drawback: it is only designed for X servers, no easy
+ * porting to non X-server based platform is offered right now, this is done
+ * in order to get a first version out of the door.
+ *
+ * Later versions should consider how to do this with more platform
+ * independence, this will probably involve changing the Painter class too.
+ */
+
+/* (Baruch Even 2000-08-05)
+ * This should be made reference counted, but for the sake of initial design
+ * I'll forego that and just make a first version that actually works, though
+ * it may fail or leak in real document, this is an initial design to try
+ * ideas on and be a testbed.
+ * It may just as well be scraped later on to create a better design based on
+ * the results of working with the current design.
+ */
+
+/// A GraphicsCache item holder.
class GraphicsCacheItem {
public:
+ /// d-tor, frees the image structures.
+ ~GraphicsCacheItem();
+
+ /// Get the height of the image. Returns -1 on error.
+ int getHeight() const { return height_; }
+
+ /// Get the width of the image. Returns -1 on error.
+ int getWidth() const { return width_; }
+
+ /// Return a pixmap that can be displayed on X server.
+ Pixmap getImage() const { return pixmap_; }
+
+ enum ImageStatus {
+ Loading = 1,
+ ErrorConverting,
+ ErrorReading,
+ Loaded
+ };
+
+ /// Is the pixmap ready for display?
+ ImageStatus getImageStatus() const { return imageStatus_; }
+
+ /// Get a notification when the image conversion is done.
+ /// used by an internal callback mechanism.
+ void imageConverted(int retval);
+
+ /// A signal objects can connect to in order to know when the image
+ /// has arrived.
+ Signal0<void> imageDone;
private:
- ///
- GraphicsCacheItem() {}
+ /// Private c-tor so that only GraphicsCache can create an instance.
+ GraphicsCacheItem();
+
+ /// Set the filename this item will be pointing too.
+ bool setFilename(string const & filename);
+
+ /// Create an XPM file version of the image.
+ bool renderXPM(string const & filename);
+
+ /// Load the image from XPM to memory Pixmap
+ void loadXPMImage();
+
///
friend class GraphicsCache;
+
+ /// The file name of the XPM file.
+ string xpmfile;
+ /// The image height
+ int height_;
+ /// The image width
+ int width_;
+ /// Is the pixmap loaded?
+ ImageStatus imageStatus_;
+ /// The image pixmap
+ Pixmap pixmap_;
+ /// The rendering object.
+ Renderer * renderer;
+
+ /// The system caller, runs the convertor.
+ Systemcalls syscall;
};
#endif
INCLUDES = -I${srcdir}/../ $(SIGC_CFLAGS)
libgraphics_la_SOURCES = \
+ Renderer.h \
+ Renderer.C \
+ XPM_Renderer.h \
+ XPM_Renderer.C \
GraphicsCache.h \
GraphicsCache.C \
GraphicsCacheItem.h \
prop[i]);
if (strcmp(p, "GHOSTVIEW") == 0) {
err = false;
+ // We free it when we leave so we don't leak.
+ XFree(p);
break;
}
XFree(p);
we need to give latex quite a few translation commands and from the
graphicx package docs it appears that it takes quite a bit of memory
on the side of TeXing.
-
+
+ * How do we handle the inline viewing? we may need to show the same image
+ in several formats (color, monochrome, grayscale) or even in different
+ sizes, not to mention rotations!
+
TODO Basics:
- * Add support for more features so that it will be useable as a drop in
- replacement to insetfig.
+ * Add support for more features so that it will be better than insetfig.
* Keep aspect ratio radio button
* Create the GraphicsCache and FormatTranslator
* If the dialog had no real change from previous time, do not mark document
as changed.
* Keep a tab on the image file, if it changes, update the lyx view.
+ * The image choosing dialog could show thumbnails of the image formats
+ it knows of, thus selection based on the image instead of based on
+ filename.
*/
/* NOTES:
* This means to add the image inside the LyX file, usefull when
* transferring the file around.
*/
+
#ifdef __GNUG__
#pragma implementation
InsetGraphics::InsetGraphics()
#ifdef IG_OLDPARAMS
: use_bb(false), hiresbb(false), angle(0.0), origin(DEFAULT)
- ,keepaspectratio(false), scale(0.0), clip(false), draft(false)
+ ,keepaspectratio(false), scale(0.0), clip(false), draft(false)
#endif
+ : cachehandle(0), bv_(0)
{}
InsetGraphics::~InsetGraphics()
int InsetGraphics::ascent(BufferView *, LyXFont const &) const
{
-
- return 25;
+ if (cachehandle &&
+ cachehandle->getImageStatus() == GraphicsCacheItem::Loaded)
+ return cachehandle->getHeight();
+ else
+ return 50;
}
int InsetGraphics::descent(BufferView *, LyXFont const &) const
{
// this is not true if viewport is used and clip is not.
- return 25;
+ return 0;
}
int InsetGraphics::width(BufferView *, LyXFont const &) const
{
- // Need to replace this with data coming from GraphicsCache
-#ifdef IG_OLDPARAMS
- if (bb.isSet()) {
- return bb.urx - bb.llx + 2;
- }
-#endif
- return 50;
+ if (cachehandle &&
+ cachehandle->getImageStatus() == GraphicsCacheItem::Loaded)
+ return cachehandle->getWidth();
+ else
+ return 50;
}
{
Painter & paint = bv->painter();
+
// This will draw the graphics. As for now we only draw a
// placeholder rectangele.
- paint.rectangle(int(x)+2, baseline - ascent(bv, font),
+ if (cachehandle &&
+ cachehandle->getImageStatus() == GraphicsCacheItem::Loaded) {
+
+ paint.pixmap(int(x)+2, baseline - ascent(bv, font),
+ width(bv, font) - 4,
+ ascent(bv,font) + descent(bv,font),
+ cachehandle->getImage());
+ } else {
+ paint.rectangle(int(x)+2, baseline - ascent(bv, font),
width(bv, font) - 4,
ascent(bv, font) + descent(bv, font));
+
+ }
+
+ x += width(bv, font);
}
void InsetGraphics::Edit(BufferView *bv, int, int, unsigned int)
{
+ bv_ = bv;
bv->owner()->getDialogs() -> showGraphics(this);
}
void InsetGraphics::Write(Buffer const * buf, ostream & os) const
{
- os << "Graphics FormatVersion 1" << endl;
+ os << "GRAPHICS FormatVersion 1" << endl;
params.Write(buf, os);
}
void InsetGraphics::updateInset()
{
// If file changed...
- //graphicscache.addFile(params.filename);
- //bb = graphicscache.getBB(params.filename);
- //pixmap = graphicscache.getPixmap(params.filename);
+
+ GraphicsCache * gc = GraphicsCache::getInstance();
+ GraphicsCacheItem * temp = 0;
+
+ if (!params.filename.empty()) {
+ temp = gc->addFile(params.filename);
+ if (temp)
+ temp->imageDone.connect(slot(this, &InsetGraphics::imageDone));
+ }
+
+ delete cachehandle;
+ cachehandle = temp;
+
+}
+
+void InsetGraphics::imageDone()
+{
+ if (bv_)
+ bv_->updateInset(this, false);
}
bool InsetGraphics::setParams(InsetGraphicsParams const & params)
{
- // TODO: Make it return true only when the data has been changed.
- // for this to work we still need to implement operator == in
- // InsetGraphicsParams
+ // If nothing is changed, just return and say so.
if (this->params == params)
return false;
#ifndef INSET_GRAPHICS_H
#define INSET_GRAPHICS_H
+
#ifdef __GNUG__
#pragma interface
#endif
+#include <config.h>
+
#include "insets/lyxinset.h"
#include "insets/insetgraphicsParams.h"
#include "sigc++/signal_system.h"
#ifdef SIGC_CXX_NAMESPACES
using SigC::Signal0;
+using SigC::slot;
+using SigC::Object;
#endif
class Dialogs;
class GraphicsCacheItem;
///
-class InsetGraphics : public Inset {
+#ifdef SIGC_CXX_NAMESPACES
+class InsetGraphics : public Inset, public SigC::Object {
+#else
+class InsetGraphics : public Inset, public Object {
+#endif
public:
///
InsetGraphics();
/// Update the inset after parameter change.
void updateInset();
+ /// Get notified when the inline image processing has finished.
+ void imageDone();
+
/// The graphics cache handle.
GraphicsCacheItem * cachehandle;
+ /// Holds the buffer view that we are associated with.
+ BufferView * bv_;
InsetGraphicsParams params;
* This file Copyright 2000 Baruch Even
* ================================================= */
+
#ifdef __GNUG__
#pragma implementation
#endif
#include <config.h>
+
#include "insetgraphicsParams.h"
#include "support/translator.h"
#include "support/filetools.h"
-#ifdef ENABLE_ASSERTIONS
#include "support/LAssert.h"
-#endif
using std::endl;
rotateOrigin = DEFAULT;
rotateAngle = 0;
-#ifdef ENABLE_ASSERTION
testInvariant();
-#endif
}
void InsetGraphicsParams::copy(InsetGraphicsParams const & igp)
rotateOrigin = igp.rotateOrigin;
rotateAngle = igp.rotateAngle;
-#ifdef ENABLE_ASSERTIONS
testInvariant();
-#endif
}
void InsetGraphicsParams::testInvariant() const
{
-#ifdef ENABLE_ASSERTIONS
// Filename might be empty (when the dialog is first created).
// Assert(!filename.empty());
Assert(rotateAngle < 360);
Assert(rotateAngle > -360);
-#endif
}
bool operator==(InsetGraphicsParams const & left,
#endif
#include <config.h>
+
#include "LString.h"
#include "buffer.h"
if (!owner->view()->insertInset(new_inset)) {
delete new_inset;
} else {
- // this is need because you don't use a inset->Edit()
- owner->view()->updateInset(new_inset, true);
+ // this is need because you don't use a inset->Edit()
+ owner->view()->updateInset(new_inset, true);
+ new_inset->Edit(owner->view(), 0, 0, 0);
}
break;
}
#ifndef TRANSLATOR_H
#define TRANSLATOR_H
-
#include <vector>
#include <utility>
#include <algorithm>
#include <functional>
+#include "support/LAssert.h"
+
// Functors used in the template.
template<typename T1, typename T2>
class equal_1st_in_pair {
/// Find the mapping for the first argument
T2 const & find(T1 const & first) const {
-#ifdef ENABLE_ASSERTIONS
Assert( ! map.empty());
-#endif
// For explanation see the next find() function.
Map::const_iterator it =
/// Find the mapping for the second argument
T1 const & find(T2 const & second) const {
-#ifdef ENABLE_ASSERTIONS
Assert( ! map.empty());
-#endif
// The idea is as follows:
// find_if() will try to compare the data in the vector with the value.