diff --git a/src/frontends/gtk/ChangeLog b/src/frontends/gtk/ChangeLog index 4049b72e3a..d34204ecb2 100644 --- a/src/frontends/gtk/ChangeLog +++ b/src/frontends/gtk/ChangeLog @@ -1,3 +1,9 @@ +2006-01-23 John Spray + * LyXGdkImage.[Ch]: replace xforms Image class + * Makefile.am: build LyXGdkImage + * GPainter.C: use new Gdk Image class + * lyx_gui.C: use new Gdk Image class, disable XSynchronize + 2006-01-21 John Spray * GBibItem.[Ch], glade/bibitem.glade: Add the bibitem dialog diff --git a/src/frontends/gtk/GPainter.C b/src/frontends/gtk/GPainter.C index 43d966ecfe..61c3f29a1f 100644 --- a/src/frontends/gtk/GPainter.C +++ b/src/frontends/gtk/GPainter.C @@ -4,6 +4,7 @@ * Licence details can be found in the file COPYING. * * \author Huang Ying + * \author John Spray * * Full author contact details are available in file CREDITS. */ @@ -21,12 +22,12 @@ #include "GPainter.h" #include "debug.h" #include "GWorkArea.h" +#include "LyXGdkImage.h" #include "lyxrc.h" #include "encoding.h" #include "language.h" #include "LColor.h" #include "xftFontLoader.h" -#include "xformsImage.h" #include "frontends/font_metrics.h" #include "codeConvert.h" @@ -186,12 +187,14 @@ void GPainter::arc(int x, int y, unsigned int w, unsigned int h, void GPainter::image(int x, int y, int w, int h, graphics::Image const & i) { - graphics::xformsImage const & image = - static_cast(i); - Pixmap pixmap = GDK_PIXMAP_XID(owner_.getPixmap()->gobj()); - GC gc = GDK_GC_XGC(owner_.getGC()->gobj()); - XCopyArea(owner_.getDisplay(), image.getPixmap(), pixmap, - gc, 0, 0, w, h, x, y); + graphics::LyXGdkImage const & image = + static_cast(i); + Glib::RefPtr const & pixbuf = image.pixbuf(); + Glib::RefPtr pixmap = owner_.getPixmap(); + + Glib::RefPtr gc = owner_.getGC(); + pixmap->draw_pixbuf (gc, pixbuf, 0, 0, x, y, w, h, + Gdk::RGB_DITHER_NONE, 0, 0); } diff --git a/src/frontends/gtk/GWorkArea.h b/src/frontends/gtk/GWorkArea.h index 09e2de0b4c..7b6bf3387c 100644 --- a/src/frontends/gtk/GWorkArea.h +++ b/src/frontends/gtk/GWorkArea.h @@ -103,7 +103,6 @@ private: /// The pixmap overlay on the workarea Glib::RefPtr workAreaPixmap_; Glib::RefPtr workAreaGC_; - /// the xforms-specific painter GPainter painter_; XftDraw * draw_; ColorHandler colorHandler_; diff --git a/src/frontends/gtk/LyXGdkImage.C b/src/frontends/gtk/LyXGdkImage.C new file mode 100644 index 0000000000..c2e4e34335 --- /dev/null +++ b/src/frontends/gtk/LyXGdkImage.C @@ -0,0 +1,289 @@ +/** + * \file LyXGdkImage.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Angus Leeming (original Qt version) + * \author John Levon (original Qt version) + * \author John Spray + * + * Full author contact details are available in file CREDITS. + */ + +#include + +// Too hard to make concept checks work with this file +#ifdef _GLIBCXX_CONCEPT_CHECKS +#undef _GLIBCXX_CONCEPT_CHECKS +#endif +#ifdef _GLIBCPP_CONCEPT_CHECKS +#undef _GLIBCPP_CONCEPT_CHECKS +#endif + + + +#include "LyXGdkImage.h" + +#include "debug.h" +#include "format.h" + +#include "graphics/GraphicsParams.h" + +#include "support/lstrings.h" // lowercase + +#include +#include + +using lyx::support::lowercase; + +using boost::bind; + +using std::endl; +using std::equal_to; +using std::find_if; +using std::string; + + +namespace lyx { +namespace graphics { + +/// Access to this class is through this static method. +Image::ImagePtr LyXGdkImage::newImage() +{ + ImagePtr ptr; + ptr.reset(new LyXGdkImage); + return ptr; +} + + +/// Return the list of loadable formats. +Image::FormatList LyXGdkImage::loadableFormats() +{ + static FormatList fmts; + + if (!fmts.empty()) + return fmts; + + // The formats recognised by LyX + Formats::const_iterator begin = formats.begin(); + Formats::const_iterator end = formats.end(); + + lyxerr[Debug::GRAPHICS] + << "\nThe image loader can load the following directly:\n"; + + Gdk::Pixbuf::SListHandle_PixbufFormat gdkformats = Gdk::Pixbuf::get_formats(); + Gdk::Pixbuf::SListHandle_PixbufFormat::iterator it = gdkformats.begin(); + Gdk::Pixbuf::SListHandle_PixbufFormat::iterator gdk_end = gdkformats.end(); + + for (; it != gdk_end; ++it) { + Gdk::PixbufFormat thisformat = (*it); + lyxerr[Debug::GRAPHICS] << thisformat.get_name() << endl; + + std::vector extensions = thisformat.get_extensions(); + std::vector::const_iterator ext_end = extensions.end(); + std::vector::iterator ext_it = extensions.begin(); + for (; ext_it != ext_end; ++ext_it) { + std::string ext = lowercase(*ext_it); + Formats::const_iterator fit = + find_if(begin, end, + bind(equal_to(), + bind(&Format::extension, _1), + ext)); + if (fit != end) + fmts.push_back(fit->name()); + } + } + + if (lyxerr.debugging()) { + lyxerr[Debug::GRAPHICS] + << "\nOf these, LyX recognises the following formats:\n"; + + FormatList::const_iterator fbegin = fmts.begin(); + FormatList::const_iterator fend = fmts.end(); + for (FormatList::const_iterator fit = fbegin; fit != fend; ++fit) { + if (fit != fbegin) + lyxerr[Debug::GRAPHICS] << ", "; + lyxerr[Debug::GRAPHICS] << *fit; + } + lyxerr[Debug::GRAPHICS] << '\n' << endl; + } + + return fmts; +} + + +LyXGdkImage::LyXGdkImage() + : Image() +{ +} + + +LyXGdkImage::LyXGdkImage(LyXGdkImage const & other) + : Image(other), original_(other.original_), + transformed_(other.transformed_) +{} + + +Image * LyXGdkImage::clone_impl() const +{ + return new LyXGdkImage(*this); +} + + +unsigned int LyXGdkImage::getWidth_impl() const +{ + return transformed_->get_width(); +} + + +unsigned int LyXGdkImage::getHeight_impl() const +{ + return transformed_->get_height(); +} + + +void LyXGdkImage::load_impl(string const & filename) +{ + if (original_) { + lyxerr[Debug::GRAPHICS] + << "Image is loaded already!" << endl; + finishedLoading(false); + return; + } + + original_ = Gdk::Pixbuf::create_from_file(filename); + + if (!original_){ + lyxerr[Debug::GRAPHICS] + << "Unable to open image" << endl; + finishedLoading(false); + return; + } + + transformed_ = original_; + finishedLoading(true); +} + +/* +namespace { + +// This code is taken from KImageEffect::toGray +QImage & toGray(QImage & img) +{ + if (img.width() == 0 || img.height() == 0) + return img; + + int const pixels = img.depth() > 8 ? + img.width() * img.height() : img.numColors(); + + unsigned int * const data = img.depth() > 8 ? + (unsigned int *)img.bits() : + (unsigned int *)img.colorTable(); + + for(int i = 0; i < pixels; ++i){ + int const val = qGray(data[i]); + data[i] = qRgba(val, val, val, qAlpha(data[i])); + } + return img; +} + +} // namespace anon +*/ + +bool LyXGdkImage::setPixmap_impl(Params const & params) +{ + if (!original_ || params.display == NoDisplay) + return false; + + // TODO: implement grayscale and monochrome + switch (params.display) { + case GrayscaleDisplay: { + //toGray(transformed_); + //transformed_->saturate_and_pixelate (dest, 0.0, false); + break; + } + + case MonochromeDisplay: { + //transformed_.convertDepth(transformed_.depth(), Qt::MonoOnly); + break; + } + + default: + break; + } + + return true; +} + + +void LyXGdkImage::clip_impl(Params const & params) +{ + if (!transformed_) + return; + + if (params.bb.empty()) + // No clipping is necessary. + return; + + int const new_width = params.bb.xr - params.bb.xl; + int const new_height = params.bb.yt - params.bb.yb; + + // No need to check if the width, height are > 0 because the + // Bounding Box would be empty() in this case. + if (new_width > original_->get_width() || new_height > original_->get_height()) { + // Bounds are invalid. + return; + } + + if (new_width == original_->get_width() && new_height == original_->get_height()) + return; + + int const xoffset_l = params.bb.xl; + int const yoffset_t = (original_->get_height() > int(params.bb.yt) ? + original_->get_height() - params.bb.yt : 0); + + transformed_ = Gdk::Pixbuf::create_subpixbuf(original_, + xoffset_l, yoffset_t, new_width, new_height); +} + + +void LyXGdkImage::rotate_impl(Params const & params) +{ + if (!transformed_) + return; + + if (!params.angle) + return; + + // TODO: allow free rotation + Gdk::PixbufRotation rotation = Gdk::PIXBUF_ROTATE_NONE; + if (params.angle == 90.0) + rotation = Gdk::PIXBUF_ROTATE_COUNTERCLOCKWISE; + else if (params.angle == 180.0) + rotation = Gdk::PIXBUF_ROTATE_UPSIDEDOWN; + else if (params.angle == 270.0) + rotation = Gdk::PIXBUF_ROTATE_CLOCKWISE; + + + transformed_ = transformed_->rotate_simple(rotation); +} + + +void LyXGdkImage::scale_impl(Params const & params) +{ + if (!transformed_) + return; + + unsigned int width; + unsigned int height; + boost::tie(width, height) = getScaledDimensions(params); + + if (width == getWidth() && height == getHeight()) + return; + + transformed_ = transformed_->scale_simple( + width, height, Gdk::INTERP_BILINEAR); +} + +} // namespace graphics +} // lyx diff --git a/src/frontends/gtk/LyXGdkImage.h b/src/frontends/gtk/LyXGdkImage.h new file mode 100644 index 0000000000..09341b8d19 --- /dev/null +++ b/src/frontends/gtk/LyXGdkImage.h @@ -0,0 +1,76 @@ +// -*- C++ -*- +/** + * \file GdkImage.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Angus Leeming (original Qt version) + * \author John Levon (original Qt version) + * \author John Spray + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef LYXGDKIMAGE_H +#define LYXGDKIMAGE_H + + +#include "graphics/GraphicsImage.h" + +#include + +namespace lyx { +namespace graphics { + +class LyXGdkImage : public Image { +public: + /// Access to this class is through this static method. + static ImagePtr newImage(); + + /// Return the list of loadable formats. + static FormatList loadableFormats(); + + /// Retrieve the buffered pixmap. + Glib::RefPtr const & pixbuf() const {return transformed_;} + +private: + /// Create a copy + virtual Image * clone_impl() const; + /// Get the image width + virtual unsigned int getWidth_impl() const; + /// Get the image height + virtual unsigned int getHeight_impl() const; + // FIXME Is the image drawable ? + virtual bool isDrawable_impl() const { return true; } + /** + * Load the image file into memory. + * The process is asynchronous, so this method starts the loading. + * When finished, the Image::finishedLoading signal is emitted. + */ + virtual void load_impl(std::string const & filename); + /** + * Finishes the process of modifying transformed_, using + * \c params to decide on color, grayscale etc. + * \returns true if successful. + */ + virtual bool setPixmap_impl(Params const & params); + /// Clip the image using params. + virtual void clip_impl(Params const & params); + /// Rotate the image using params. + virtual void rotate_impl(Params const & params); + /// Scale the image using params. + virtual void scale_impl(Params const & params); + + /// Access to the class is through newImage() and clone. + LyXGdkImage(); + /// + LyXGdkImage(LyXGdkImage const &); + + Glib::RefPtr original_; + Glib::RefPtr transformed_; +}; + +} // namespace graphics +} // namespace lyx + +#endif // LYXGDKIMAGE_H diff --git a/src/frontends/gtk/Makefile.am b/src/frontends/gtk/Makefile.am index 28b540ba79..8658901b3e 100644 --- a/src/frontends/gtk/Makefile.am +++ b/src/frontends/gtk/Makefile.am @@ -116,6 +116,8 @@ libgtk_la_SOURCES = \ GtkmmX.h \ IdSc.C \ IdSc.h \ + LyXGdkImage.C \ + LyXGdkImage.h \ LyXKeySymFactory.C \ LyXScreenFactory.C \ WorkAreaFactory.C \ diff --git a/src/frontends/gtk/lyx_gui.C b/src/frontends/gtk/lyx_gui.C index 6ae85905a7..6b45f4e981 100644 --- a/src/frontends/gtk/lyx_gui.C +++ b/src/frontends/gtk/lyx_gui.C @@ -50,7 +50,6 @@ //just for xforms #include "lyx_forms.h" -#include "xformsImage.h" #include "xforms_helpers.h" #include "support/lyxlib.h" @@ -60,6 +59,8 @@ #include +#include "LyXGdkImage.h" + #include #include #include @@ -192,11 +193,6 @@ void parse_init_xforms(int & argc, char * argv[]) XSetErrorHandler(LyX_XErrHandler); - using namespace lyx::graphics; - - // connect the image loader based on the xforms library - Image::newImage = boost::bind(&xformsImage::newImage); - Image::loadableFormats = boost::bind(&xformsImage::loadableFormats); } @@ -206,6 +202,10 @@ void lyx_gui::parse_init(int & argc, char * argv[]) parse_init_xforms(argc, argv); + using namespace lyx::graphics; + Image::newImage = boost::bind(&LyXGdkImage::newImage); + Image::loadableFormats = boost::bind(&LyXGdkImage::loadableFormats); + locale_init(); // must do this /before/ lyxrc gets read @@ -335,7 +335,7 @@ void lyx_gui::start(string const & batch, std::vector const & files) { start_xforms(); // just for debug - XSynchronize(getDisplay(), true); + //XSynchronize(getDisplay(), true); boost::shared_ptr view_ptr(new GView); LyX::ref().addLyXView(view_ptr);