On Tuesday 02 July 2002 12:25 pm, Andre Poenitz wrote: > On Tue, Jul 02, 2002 at 01:13:26PM +0200, David Kastrup wrote: > > Well, if you have any mechanisms for xdviing/ghostviewing just part of > > a document, "local" defines will fail anyway if not included in such > > a region. I would class operation of previews similarly: defs > > relevant to a preview should be placed either in the preamble, or > > inside of the previewed material itself. > > > > Catering for more is being too clever, I think. Let the user suffer > > the consequences. > > I think it should get possible to get closer to the proper settings some > day. Currently just using the preamble is probably the best trade-off > between correctness and required work.
Indeed. Attached is a prototype PreviewQueue class. Currently it does no more than compile, but I believe it's fairly complete. Note that I iterate over all MATHMACROs when I dump the preamble so we'll get previews of "reasonable" math insets. I think that Buffer would have a boost::scoped_ptr<grfx::PreviewQueue> previewer_; member and that it would be passed lots of LaTeX snippets when the document was loaded. The code below will start off the conversion process, but we probably need a new Inset method to invoke grfx::PreviewQueue::addSnippet and connect to grfx::PreviewQueue::readyToLoad. Anyway, you get the idea. Feel free to comment. Angus void Buffer::initiatePreview() const { // Loop over the insets and pass those of type MATH_CODE to // the PreviewQueue Buffer::inset_iterator it = buffer_.inset_const_iterator_begin(); Buffer::inset_iterator end = buffer_.inset_const_iterator_end(); for (; it != end; ++it) { if ((*it)->lyxCode() == Inset::MATH_CODE) { ostringstream os; (*it)->latex(*this, os, true, true); previewer_->addSnippet(os.str().c_str()); } } previewer_.startProcessing(); }
// -*- C++ -*- /** * \file GraphicsPreview.h * Copyright 2002 the LyX Team * Read the file COPYING * * \author Angus Leeming <[EMAIL PROTECTED]> * * grfx::PreviewQueue collects latex snippets together. Then, on a * startProcessing() call, these are dumped to file and processed, converting * each snippet to a separate bitmap image file. Once a bitmap file is ready * to be loaded back into LyX, the PreviewQueue emits a readyToLoad signal * to inform the initiating process. */ #ifndef GRAPHICSPREVIEW_H #define GRAPHICSPREVIEW_H #ifdef __GNUG__ #pragma interface #endif #include "LString.h" #include <boost/utility.hpp> #include <boost/scoped_ptr.hpp> #include <boost/signals/signal2.hpp> class Buffer; namespace grfx { class PreviewQueue : boost::noncopyable { public: /** We pass a Buffer copy & so that we can dump the preamble to the * LaTeX file. */ PreviewQueue(Buffer const &); /// ~PreviewQueue(); /// Add a snippet of LaTeX to the queue for processing. void addSnippet(string const & latex_snippet); /** We have accumulated several latex snippets. * Initiate the transformation into bitmap image files. */ void startProcessing(); /** Emit this signal when the image file is ready to load. * Passes the LaTeX snippet and the name of the associated * bitmap image file to load that is now ready. */ boost::signal2<void, string const &, string const &> readyToLoad; private: /// Use the Pimpl idiom to hide the internals. class Impl; /// The pointer never changes although *pimpl_'s contents may. boost::scoped_ptr<Impl> const pimpl_; }; } // namespace grfx #endif // GRAPHICSPREVIEW_H
/* * \file GraphicsPreview.C * Copyright 2002 the LyX Team * Read the file COPYING * * \author Angus Leeming <[EMAIL PROTECTED]> */ #include <config.h> #ifdef __GNUG__ #pragma implementation #endif #include "GraphicsPreview.h" #include "buffer.h" #include "bufferparams.h" #include "debug.h" #include "lyxrc.h" #include "LColor.h" #include "LaTeXFeatures.h" // temporary (buffer should do this). #include "insets/inset.h" #include "support/filetools.h" #include "support/forkedcall.h" #include "support/lstrings.h" #include "support/lyxlib.h" #include "Lsstream.h" // temporary (hexname) #include <X11/X.h> // temporary (hexname) #include FORMS_H_LOCATION // temporary (hexname) #include <boost/bind.hpp> #include <boost/signals/trackable.hpp> #include <fstream> #include <iomanip> #include <map> using std::endl; using std::ofstream; using std::ostream; using std::setbase; using std::setfill; using std::setw; namespace { string const unique_filename() { static string const dir = OnlyPath(lyx::tempName()); static int theCounter = 0; ostringstream os; os << dir << theCounter++ << "lyxpreview"; return os.str().c_str(); } // These are hard-coded for now. // Replace eventually with a lyxrc variable. string const preview_script("~/.lyx-1.3.0cvs/scripts/lyxpreview2ppm.sh"); string const final_format("ppm"); // This should go into lyx_gui string const hexname(LColor::color const & col) { string const name = lcolor.getX11Name(col); Display * display = fl_get_display();; Colormap const colormap = fl_state[fl_get_vclass()].colormap; XColor xcol, ccol; if (XLookupColor(display, colormap, name.c_str(), &xcol, &ccol) == 0) { lyxerr << "X can't find color \"" << lcolor.getLyXName(col) << endl; return string(); } ostringstream os; // Note that X stores the RGB values in the range 0 - 65535 // whilst we require them in the range 0 - 255. os << setbase(16) << setfill('0') << setw(2) << (xcol.red / 256) << setw(2) << (xcol.green / 256) << setw(2) << (xcol.blue / 256); return os.str().c_str(); } } // namespace anon namespace grfx { struct PreviewQueue::Impl : public boost::signals::trackable { /// Impl(PreviewQueue & p, Buffer const & b); /// void addSnippet(string const & latex_snippet); /// void startProcessing(); /// Invoked by Forkedcall on finish void finishedProcessing(string const &, pid_t, int); private: /// ostream & dumpPreamble(ostream &) const; /// ostream & dumpData(ostream &) const; /** The map stores the LaTeX snippet and the name of the generated * bitmap image file. * Allows repeated snippets to be caught and discarded before the * LaTeX file is dumped and processing begins. */ typedef std::map<string, string> DataType; /// DataType data; /// string filename_base_; /// PreviewQueue & parent_; /// Buffer const & buffer_; }; PreviewQueue::PreviewQueue(Buffer const & b) : pimpl_(new Impl(*this, b)) {} PreviewQueue::~PreviewQueue() {} void PreviewQueue::addSnippet(string const & latex_snippet) { pimpl_->addSnippet(latex_snippet); } void PreviewQueue::startProcessing() { pimpl_->startProcessing(); } PreviewQueue::Impl::Impl(PreviewQueue & p, Buffer const & b) : filename_base_(unique_filename()), parent_(p), buffer_(b) {} void PreviewQueue::Impl::addSnippet(string const & latex_snippet) { DataType::const_iterator it = data.find(latex_snippet); if (it != data.end()) return; static int theCounter = 1; ostringstream os; os << filename_base_ << std::setfill('0') << setw(3) << theCounter++ << "." << final_format; string const image_filename = os.str().c_str(); data[latex_snippet] = image_filename; } void PreviewQueue::Impl::startProcessing() { string const latexfile = filename_base_ + ".tex"; // Output the LaTeX file. ofstream of(latexfile.c_str()); of << "\\batchmode" << dumpPreamble(of) << "\\begin{document}" << dumpData(of) << "\\end{document}\n"; of.close(); // Clear the data so we're ready to start again data.clear(); // The conversion command. ostringstream cs; cs << "sh " << preview_script << " " << latexfile << " " << tostr(lyxrc.dpi * lyxrc.zoom); string const command = cs.str().c_str(); // Initiate the conversion Forkedcall::SignalTypePtr convert_ptr; convert_ptr.reset(new Forkedcall::SignalType); convert_ptr->connect( boost::bind(&Impl::finishedProcessing, this, _1, _2, _3)); Forkedcall call; call.startscript(command, convert_ptr); // Reset the filename filename_base_ = unique_filename(); } void PreviewQueue::Impl::finishedProcessing(string const & /* cmd */, pid_t /* pid */, int retval) { if (retval > 0) return; DataType::const_iterator it = data.begin(); DataType::const_iterator end = data.end(); for (; it != end; ++it) { parent_.readyToLoad(it->first, it->second); } } ostream & PreviewQueue::Impl::dumpPreamble(ostream & os) const { LaTeXFeatures features(buffer_.params); string tmp = features.getPackages(); if (!tmp.empty()) os << tmp << '\n'; tmp = features.getMacros(); if (!tmp.empty()) os << tmp << '\n'; tmp = features.getTClassPreamble(); if (!tmp.empty()) os << tmp << '\n'; tmp = buffer_.params.preamble; if (!tmp.empty()) os << tmp << '\n'; // Loop over the insets in the buffer and insert all the math-macros Buffer::inset_iterator it = buffer_.inset_const_iterator_begin(); Buffer::inset_iterator end = buffer_.inset_const_iterator_end(); for (; it != end; ++it) { if ((*it)->lyxCode() == Inset::MATHMACRO_CODE) { (*it)->latex(&buffer_, os, true, true); } } // Use the preview style file to ensure that each snippet appears on a // fresh page os << "\\usepackage[active,dvips,tightpage]{preview}\n\n"; // This piece of PostScript magic ensures that the foreground and // background colors are the same as the LyX screen. string fg = hexname(LColor::foreground); if (fg.empty()) fg = "000000"; string bg = hexname(LColor::background); if (bg.empty()) bg = "ffffff"; os << "\\AtBeginDocument{\\AtBeginDvi{%\n" << "\\special{!userdict begin/bop-hook{//bop-hook exec\n" << "<" << fg << bg << ">{255 div}forall setrgbcolor\n" << "clippath fill setrgbcolor}bind def end}}}\n"; return os; } ostream & PreviewQueue::Impl::dumpData(ostream & os) const { DataType::const_iterator it = data.begin(); DataType::const_iterator end = data.end(); for (; it != end; ++it) { os << "\\begin{preview}\n" << it->first << '\n' << "\\end{preview}\n"; } return os; } } // namespace grfx