From: Bo Peng Date: Wed, 25 Apr 2007 03:03:25 +0000 (+0000) Subject: Rename files in src/mathed and src/graphics from .C to .cpp, step 2 X-Git-Tag: 1.6.10~10107 X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=f497296c30e6da2f97b16da8ad1c9e96feffb16b;p=features.git Rename files in src/mathed and src/graphics from .C to .cpp, step 2 git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@17969 a592a061-630c-0410-9148-cb99ea01b6c8 --- diff --git a/src/graphics/GraphicsCache.C b/src/graphics/GraphicsCache.C deleted file mode 100644 index 10f9fc7a73..0000000000 --- a/src/graphics/GraphicsCache.C +++ /dev/null @@ -1,114 +0,0 @@ -/** - * \file GraphicsCache.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Baruch Even - * \author Angus Leeming - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "GraphicsCache.h" -#include "GraphicsCacheItem.h" -#include "GraphicsImage.h" - -#include "debug.h" - -#include "support/filetools.h" - -#include - -using std::string; - - -namespace lyx { - -using support::FileName; - -namespace graphics { - -/** The cache contains one item per file, so use a map to find the - * cache item quickly by filename. - */ -typedef std::map CacheType; - -class Cache::Impl { -public: - /// - CacheType cache; -}; - - -Cache & Cache::get() -{ - // Now return the cache - static Cache singleton; - return singleton; -} - - -Cache::Cache() - : pimpl_(new Impl) -{} - - -Cache::~Cache() -{} - - -std::vector Cache::loadableFormats() const -{ - return Image::loadableFormats(); -} - - -void Cache::add(FileName const & file) const -{ - // Is the file in the cache already? - if (inCache(file)) { - LYXERR(Debug::GRAPHICS) << "Cache::add(" << file << "):\n" - << "The file is already in the cache." - << std::endl; - return; - } - - pimpl_->cache[file] = ItemPtr(new CacheItem(file)); -} - - -void Cache::remove(FileName const & file) const -{ - CacheType::iterator it = pimpl_->cache.find(file); - if (it == pimpl_->cache.end()) - return; - - ItemPtr & item = it->second; - - if (item.use_count() == 1) { - // The graphics file is in the cache, but nothing else - // references it. - pimpl_->cache.erase(it); - } -} - - -bool Cache::inCache(FileName const & file) const -{ - return pimpl_->cache.find(file) != pimpl_->cache.end(); -} - - -Cache::ItemPtr const Cache::item(FileName const & file) const -{ - CacheType::const_iterator it = pimpl_->cache.find(file); - if (it == pimpl_->cache.end()) - return ItemPtr(); - - return it->second; -} - -} // namespace graphics -} // namespace lyx diff --git a/src/graphics/GraphicsCache.cpp b/src/graphics/GraphicsCache.cpp new file mode 100644 index 0000000000..10f9fc7a73 --- /dev/null +++ b/src/graphics/GraphicsCache.cpp @@ -0,0 +1,114 @@ +/** + * \file GraphicsCache.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Baruch Even + * \author Angus Leeming + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "GraphicsCache.h" +#include "GraphicsCacheItem.h" +#include "GraphicsImage.h" + +#include "debug.h" + +#include "support/filetools.h" + +#include + +using std::string; + + +namespace lyx { + +using support::FileName; + +namespace graphics { + +/** The cache contains one item per file, so use a map to find the + * cache item quickly by filename. + */ +typedef std::map CacheType; + +class Cache::Impl { +public: + /// + CacheType cache; +}; + + +Cache & Cache::get() +{ + // Now return the cache + static Cache singleton; + return singleton; +} + + +Cache::Cache() + : pimpl_(new Impl) +{} + + +Cache::~Cache() +{} + + +std::vector Cache::loadableFormats() const +{ + return Image::loadableFormats(); +} + + +void Cache::add(FileName const & file) const +{ + // Is the file in the cache already? + if (inCache(file)) { + LYXERR(Debug::GRAPHICS) << "Cache::add(" << file << "):\n" + << "The file is already in the cache." + << std::endl; + return; + } + + pimpl_->cache[file] = ItemPtr(new CacheItem(file)); +} + + +void Cache::remove(FileName const & file) const +{ + CacheType::iterator it = pimpl_->cache.find(file); + if (it == pimpl_->cache.end()) + return; + + ItemPtr & item = it->second; + + if (item.use_count() == 1) { + // The graphics file is in the cache, but nothing else + // references it. + pimpl_->cache.erase(it); + } +} + + +bool Cache::inCache(FileName const & file) const +{ + return pimpl_->cache.find(file) != pimpl_->cache.end(); +} + + +Cache::ItemPtr const Cache::item(FileName const & file) const +{ + CacheType::const_iterator it = pimpl_->cache.find(file); + if (it == pimpl_->cache.end()) + return ItemPtr(); + + return it->second; +} + +} // namespace graphics +} // namespace lyx diff --git a/src/graphics/GraphicsCacheItem.C b/src/graphics/GraphicsCacheItem.C deleted file mode 100644 index 74e9eb4127..0000000000 --- a/src/graphics/GraphicsCacheItem.C +++ /dev/null @@ -1,451 +0,0 @@ -/** - * \file GraphicsCacheItem.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Baruch Even - * \author Herbert Voß - * \author Angus Leeming - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "GraphicsCacheItem.h" -#include "GraphicsConverter.h" -#include "GraphicsImage.h" - -#include "ConverterCache.h" -#include "debug.h" -#include "format.h" - -#include "support/filetools.h" -#include "support/FileMonitor.h" -#include "support/lyxlib.h" - -#include - - -namespace lyx { - -using support::FileMonitor; -using support::FileName; -using support::isFileReadable; -using support::makeDisplayPath; -using support::onlyFilename; -using support::tempName; -using support::unlink; -using support::unzipFile; -using support::zippedFile; - -using std::endl; -using std::string; - - -namespace graphics { - -class CacheItem::Impl : public boost::signals::trackable { -public: - - /// - Impl(FileName const & file); - - /** Start the image conversion process, checking first that it is - * necessary. If it is necessary, then a conversion task is started. - * CacheItem asumes that the conversion is asynchronous and so - * passes a Signal to the converting routine. When the conversion - * is finished, this Signal is emitted, returning the converted - * file to this->imageConverted. - * - * If no file conversion is needed, then convertToDisplayFormat() calls - * loadImage() directly. - * - * convertToDisplayFormat() will set the loading status flag as - * approriate through calls to setStatus(). - */ - void convertToDisplayFormat(); - - /** Load the image into memory. This is called either from - * convertToDisplayFormat() direct or from imageConverted(). - */ - void loadImage(); - - /** Get a notification when the image conversion is done. - * Connected to a signal on_finish_ which is passed to - * Converter::convert. - */ - void imageConverted(bool); - - /** Get a notification when the image loading is done. - * Connected to a signal on_finish_ which is passed to - * lyx::graphics::Image::loadImage. - */ - void imageLoaded(bool); - - /** Sets the status of the loading process. Also notifies - * listeners that the status has changed. - */ - void setStatus(ImageStatus new_status); - - /** Can be invoked directly by the user, but is also connected to the - * FileMonitor and so is invoked when the file is changed - * (if monitoring is taking place). - */ - void startLoading(); - - /** If we are asked to load the file for a second or further time, - * (because the file has changed), then we'll have to first reset - * many of the variables below. - */ - void reset(); - - /// The filename we refer too. - FileName const filename_; - /// - FileMonitor const monitor_; - - /// Is the file compressed? - bool zipped_; - /// If so, store the uncompressed file in this temporary file. - FileName unzipped_filename_; - /// The target format - string to_; - /// What file are we trying to load? - FileName file_to_load_; - /** Should we delete the file after loading? True if the file is - * the result of a conversion process. - */ - bool remove_loaded_file_; - - /// The image and its loading status. - boost::shared_ptr image_; - /// - ImageStatus status_; - - /// This signal is emitted when the image loading status changes. - boost::signal statusChanged; - - /// The connection to the signal Image::finishedLoading - boost::signals::connection cl_; - - /// The connection of the signal ConvProcess::finishedConversion, - boost::signals::connection cc_; - - /// - boost::scoped_ptr converter_; -}; - - -CacheItem::CacheItem(FileName const & file) - : pimpl_(new Impl(file)) -{} - - -CacheItem::~CacheItem() -{} - - -FileName const & CacheItem::filename() const -{ - return pimpl_->filename_; -} - - -void CacheItem::startLoading() const -{ - pimpl_->startLoading(); -} - - -void CacheItem::startMonitoring() const -{ - if (!pimpl_->monitor_.monitoring()) - pimpl_->monitor_.start(); -} - - -bool CacheItem::monitoring() const -{ - return pimpl_->monitor_.monitoring(); -} - - -unsigned long CacheItem::checksum() const -{ - return pimpl_->monitor_.checksum(); -} - - -Image const * CacheItem::image() const -{ - return pimpl_->image_.get(); -} - - -ImageStatus CacheItem::status() const -{ - return pimpl_->status_; -} - - -boost::signals::connection CacheItem::connect(slot_type const & slot) const -{ - return pimpl_->statusChanged.connect(slot); -} - - -//------------------------------ -// Implementation details follow -//------------------------------ - - -CacheItem::Impl::Impl(FileName const & file) - : filename_(file), - monitor_(file, 2000), - zipped_(false), - remove_loaded_file_(false), - status_(WaitingToLoad) -{ - monitor_.connect(boost::bind(&Impl::startLoading, this)); -} - - -void CacheItem::Impl::startLoading() -{ - if (status_ != WaitingToLoad) - reset(); - - convertToDisplayFormat(); -} - - -void CacheItem::Impl::reset() -{ - zipped_ = false; - if (!unzipped_filename_.empty()) - unlink(unzipped_filename_); - unzipped_filename_.erase(); - - if (remove_loaded_file_ && !file_to_load_.empty()) - unlink(file_to_load_); - remove_loaded_file_ = false; - file_to_load_.erase(); - to_.erase(); - - if (image_.get()) - image_.reset(); - - status_ = WaitingToLoad; - - if (cl_.connected()) - cl_.disconnect(); - - if (cc_.connected()) - cc_.disconnect(); - - if (converter_.get()) - converter_.reset(); -} - - -void CacheItem::Impl::setStatus(ImageStatus new_status) -{ - if (status_ == new_status) - return; - - status_ = new_status; - statusChanged(); -} - - -void CacheItem::Impl::imageConverted(bool success) -{ - string const text = success ? "succeeded" : "failed"; - LYXERR(Debug::GRAPHICS) << "Image conversion " << text << '.' << endl; - - file_to_load_ = converter_.get() ? - FileName(converter_->convertedFile()) : FileName(); - converter_.reset(); - cc_.disconnect(); - - success = !file_to_load_.empty() && isFileReadable(file_to_load_); - - if (!success) { - LYXERR(Debug::GRAPHICS) << "Unable to find converted file!" - << endl; - setStatus(ErrorConverting); - - if (zipped_) - unlink(unzipped_filename_); - - return; - } - - // Add the converted file to the file cache - ConverterCache::get().add(filename_, to_, file_to_load_); - - loadImage(); -} - - -// This function gets called from the callback after the image has been -// converted successfully. -void CacheItem::Impl::loadImage() -{ - setStatus(Loading); - LYXERR(Debug::GRAPHICS) << "Loading image." << endl; - - image_ = Image::newImage(); - - cl_.disconnect(); - cl_ = image_->finishedLoading.connect( - boost::bind(&Impl::imageLoaded, this, _1)); - image_->load(file_to_load_); -} - - -void CacheItem::Impl::imageLoaded(bool success) -{ - string const text = success ? "succeeded" : "failed"; - LYXERR(Debug::GRAPHICS) << "Image loading " << text << '.' << endl; - - // Clean up after loading. - if (zipped_) - unlink(unzipped_filename_); - - if (remove_loaded_file_ && unzipped_filename_ != file_to_load_) - unlink(file_to_load_); - - cl_.disconnect(); - - if (!success) { - setStatus(ErrorLoading); - return; - } - - // Inform the outside world. - setStatus(Loaded); -} - - -static string const findTargetFormat(string const & from) -{ - typedef lyx::graphics::Image::FormatList FormatList; - FormatList const formats = lyx::graphics::Image::loadableFormats(); - - // There must be a format to load from. - BOOST_ASSERT(!formats.empty()); - - // Use the standard converter if we don't know the format to load - // from. - if (from.empty()) - return string("ppm"); - - // First ascertain if we can load directly with no conversion - FormatList::const_iterator it = formats.begin(); - FormatList::const_iterator end = formats.end(); - for (; it != end; ++it) { - if (from == *it) - return *it; - } - - // So, we have to convert to a loadable format. Can we? - it = formats.begin(); - for (; it != end; ++it) { - if (lyx::graphics::Converter::isReachable(from, *it)) - return *it; - else - LYXERR(Debug::GRAPHICS) - << "Unable to convert from " << from - << " to " << *it << std::endl; - } - - // Failed! so we have to try to convert it to PPM format - // with the standard converter - return string("ppm"); -} - - -void CacheItem::Impl::convertToDisplayFormat() -{ - setStatus(Converting); - - // First, check that the file exists! - if (!isFileReadable(filename_)) { - if (status_ != ErrorNoFile) { - setStatus(ErrorNoFile); - LYXERR(Debug::GRAPHICS) - << "\tThe file is not readable" << endl; - } - return; - } - - // Make a local copy in case we unzip it - FileName filename; - zipped_ = zippedFile(filename_); - if (zipped_) { - unzipped_filename_ = tempName(FileName(), filename_.toFilesystemEncoding()); - if (unzipped_filename_.empty()) { - setStatus(ErrorConverting); - LYXERR(Debug::GRAPHICS) - << "\tCould not create temporary file." << endl; - return; - } - filename = unzipFile(filename_, unzipped_filename_.toFilesystemEncoding()); - } else - filename = filename_; - - docstring const displayed_filename = makeDisplayPath(filename_.absFilename()); - LYXERR(Debug::GRAPHICS) << "[graphics::CacheItem::Impl::convertToDisplayFormat]\n" - << "\tAttempting to convert image file: " << filename - << "\n\twith displayed filename: " << lyx::to_utf8(displayed_filename) - << endl; - - string const from = formats.getFormatFromFile(filename); - if (from.empty()) { - setStatus(ErrorConverting); - LYXERR(Debug::GRAPHICS) - << "\tCould not determine file format." << endl; - } - LYXERR(Debug::GRAPHICS) - << "\n\tThe file contains " << from << " format data." << endl; - to_ = findTargetFormat(from); - - if (from == to_) { - // No conversion needed! - LYXERR(Debug::GRAPHICS) << "\tNo conversion needed (from == to)!" << endl; - file_to_load_ = filename; - loadImage(); - return; - } - - if (ConverterCache::get().inCache(filename, to_)) { - LYXERR(Debug::GRAPHICS) << "\tNo conversion needed (file in file cache)!" - << endl; - file_to_load_ = ConverterCache::get().cacheName(filename, to_); - loadImage(); - return; - } - - LYXERR(Debug::GRAPHICS) << "\tConverting it to " << to_ << " format." << endl; - - // Add some stuff to create a uniquely named temporary file. - // This file is deleted in loadImage after it is loaded into memory. - FileName const to_file_base(tempName(FileName(), "CacheItem")); - remove_loaded_file_ = true; - - // Remove the temp file, we only want the name... - // FIXME: This is unsafe! - unlink(to_file_base); - - // Connect a signal to this->imageConverted and pass this signal to - // the graphics converter so that we can load the modified file - // on completion of the conversion process. - converter_.reset(new Converter(filename, to_file_base.absFilename(), from, to_)); - converter_->connect(boost::bind(&Impl::imageConverted, this, _1)); - converter_->startConversion(); -} - -} // namespace graphics -} // namespace lyx diff --git a/src/graphics/GraphicsCacheItem.cpp b/src/graphics/GraphicsCacheItem.cpp new file mode 100644 index 0000000000..74e9eb4127 --- /dev/null +++ b/src/graphics/GraphicsCacheItem.cpp @@ -0,0 +1,451 @@ +/** + * \file GraphicsCacheItem.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Baruch Even + * \author Herbert Voß + * \author Angus Leeming + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "GraphicsCacheItem.h" +#include "GraphicsConverter.h" +#include "GraphicsImage.h" + +#include "ConverterCache.h" +#include "debug.h" +#include "format.h" + +#include "support/filetools.h" +#include "support/FileMonitor.h" +#include "support/lyxlib.h" + +#include + + +namespace lyx { + +using support::FileMonitor; +using support::FileName; +using support::isFileReadable; +using support::makeDisplayPath; +using support::onlyFilename; +using support::tempName; +using support::unlink; +using support::unzipFile; +using support::zippedFile; + +using std::endl; +using std::string; + + +namespace graphics { + +class CacheItem::Impl : public boost::signals::trackable { +public: + + /// + Impl(FileName const & file); + + /** Start the image conversion process, checking first that it is + * necessary. If it is necessary, then a conversion task is started. + * CacheItem asumes that the conversion is asynchronous and so + * passes a Signal to the converting routine. When the conversion + * is finished, this Signal is emitted, returning the converted + * file to this->imageConverted. + * + * If no file conversion is needed, then convertToDisplayFormat() calls + * loadImage() directly. + * + * convertToDisplayFormat() will set the loading status flag as + * approriate through calls to setStatus(). + */ + void convertToDisplayFormat(); + + /** Load the image into memory. This is called either from + * convertToDisplayFormat() direct or from imageConverted(). + */ + void loadImage(); + + /** Get a notification when the image conversion is done. + * Connected to a signal on_finish_ which is passed to + * Converter::convert. + */ + void imageConverted(bool); + + /** Get a notification when the image loading is done. + * Connected to a signal on_finish_ which is passed to + * lyx::graphics::Image::loadImage. + */ + void imageLoaded(bool); + + /** Sets the status of the loading process. Also notifies + * listeners that the status has changed. + */ + void setStatus(ImageStatus new_status); + + /** Can be invoked directly by the user, but is also connected to the + * FileMonitor and so is invoked when the file is changed + * (if monitoring is taking place). + */ + void startLoading(); + + /** If we are asked to load the file for a second or further time, + * (because the file has changed), then we'll have to first reset + * many of the variables below. + */ + void reset(); + + /// The filename we refer too. + FileName const filename_; + /// + FileMonitor const monitor_; + + /// Is the file compressed? + bool zipped_; + /// If so, store the uncompressed file in this temporary file. + FileName unzipped_filename_; + /// The target format + string to_; + /// What file are we trying to load? + FileName file_to_load_; + /** Should we delete the file after loading? True if the file is + * the result of a conversion process. + */ + bool remove_loaded_file_; + + /// The image and its loading status. + boost::shared_ptr image_; + /// + ImageStatus status_; + + /// This signal is emitted when the image loading status changes. + boost::signal statusChanged; + + /// The connection to the signal Image::finishedLoading + boost::signals::connection cl_; + + /// The connection of the signal ConvProcess::finishedConversion, + boost::signals::connection cc_; + + /// + boost::scoped_ptr converter_; +}; + + +CacheItem::CacheItem(FileName const & file) + : pimpl_(new Impl(file)) +{} + + +CacheItem::~CacheItem() +{} + + +FileName const & CacheItem::filename() const +{ + return pimpl_->filename_; +} + + +void CacheItem::startLoading() const +{ + pimpl_->startLoading(); +} + + +void CacheItem::startMonitoring() const +{ + if (!pimpl_->monitor_.monitoring()) + pimpl_->monitor_.start(); +} + + +bool CacheItem::monitoring() const +{ + return pimpl_->monitor_.monitoring(); +} + + +unsigned long CacheItem::checksum() const +{ + return pimpl_->monitor_.checksum(); +} + + +Image const * CacheItem::image() const +{ + return pimpl_->image_.get(); +} + + +ImageStatus CacheItem::status() const +{ + return pimpl_->status_; +} + + +boost::signals::connection CacheItem::connect(slot_type const & slot) const +{ + return pimpl_->statusChanged.connect(slot); +} + + +//------------------------------ +// Implementation details follow +//------------------------------ + + +CacheItem::Impl::Impl(FileName const & file) + : filename_(file), + monitor_(file, 2000), + zipped_(false), + remove_loaded_file_(false), + status_(WaitingToLoad) +{ + monitor_.connect(boost::bind(&Impl::startLoading, this)); +} + + +void CacheItem::Impl::startLoading() +{ + if (status_ != WaitingToLoad) + reset(); + + convertToDisplayFormat(); +} + + +void CacheItem::Impl::reset() +{ + zipped_ = false; + if (!unzipped_filename_.empty()) + unlink(unzipped_filename_); + unzipped_filename_.erase(); + + if (remove_loaded_file_ && !file_to_load_.empty()) + unlink(file_to_load_); + remove_loaded_file_ = false; + file_to_load_.erase(); + to_.erase(); + + if (image_.get()) + image_.reset(); + + status_ = WaitingToLoad; + + if (cl_.connected()) + cl_.disconnect(); + + if (cc_.connected()) + cc_.disconnect(); + + if (converter_.get()) + converter_.reset(); +} + + +void CacheItem::Impl::setStatus(ImageStatus new_status) +{ + if (status_ == new_status) + return; + + status_ = new_status; + statusChanged(); +} + + +void CacheItem::Impl::imageConverted(bool success) +{ + string const text = success ? "succeeded" : "failed"; + LYXERR(Debug::GRAPHICS) << "Image conversion " << text << '.' << endl; + + file_to_load_ = converter_.get() ? + FileName(converter_->convertedFile()) : FileName(); + converter_.reset(); + cc_.disconnect(); + + success = !file_to_load_.empty() && isFileReadable(file_to_load_); + + if (!success) { + LYXERR(Debug::GRAPHICS) << "Unable to find converted file!" + << endl; + setStatus(ErrorConverting); + + if (zipped_) + unlink(unzipped_filename_); + + return; + } + + // Add the converted file to the file cache + ConverterCache::get().add(filename_, to_, file_to_load_); + + loadImage(); +} + + +// This function gets called from the callback after the image has been +// converted successfully. +void CacheItem::Impl::loadImage() +{ + setStatus(Loading); + LYXERR(Debug::GRAPHICS) << "Loading image." << endl; + + image_ = Image::newImage(); + + cl_.disconnect(); + cl_ = image_->finishedLoading.connect( + boost::bind(&Impl::imageLoaded, this, _1)); + image_->load(file_to_load_); +} + + +void CacheItem::Impl::imageLoaded(bool success) +{ + string const text = success ? "succeeded" : "failed"; + LYXERR(Debug::GRAPHICS) << "Image loading " << text << '.' << endl; + + // Clean up after loading. + if (zipped_) + unlink(unzipped_filename_); + + if (remove_loaded_file_ && unzipped_filename_ != file_to_load_) + unlink(file_to_load_); + + cl_.disconnect(); + + if (!success) { + setStatus(ErrorLoading); + return; + } + + // Inform the outside world. + setStatus(Loaded); +} + + +static string const findTargetFormat(string const & from) +{ + typedef lyx::graphics::Image::FormatList FormatList; + FormatList const formats = lyx::graphics::Image::loadableFormats(); + + // There must be a format to load from. + BOOST_ASSERT(!formats.empty()); + + // Use the standard converter if we don't know the format to load + // from. + if (from.empty()) + return string("ppm"); + + // First ascertain if we can load directly with no conversion + FormatList::const_iterator it = formats.begin(); + FormatList::const_iterator end = formats.end(); + for (; it != end; ++it) { + if (from == *it) + return *it; + } + + // So, we have to convert to a loadable format. Can we? + it = formats.begin(); + for (; it != end; ++it) { + if (lyx::graphics::Converter::isReachable(from, *it)) + return *it; + else + LYXERR(Debug::GRAPHICS) + << "Unable to convert from " << from + << " to " << *it << std::endl; + } + + // Failed! so we have to try to convert it to PPM format + // with the standard converter + return string("ppm"); +} + + +void CacheItem::Impl::convertToDisplayFormat() +{ + setStatus(Converting); + + // First, check that the file exists! + if (!isFileReadable(filename_)) { + if (status_ != ErrorNoFile) { + setStatus(ErrorNoFile); + LYXERR(Debug::GRAPHICS) + << "\tThe file is not readable" << endl; + } + return; + } + + // Make a local copy in case we unzip it + FileName filename; + zipped_ = zippedFile(filename_); + if (zipped_) { + unzipped_filename_ = tempName(FileName(), filename_.toFilesystemEncoding()); + if (unzipped_filename_.empty()) { + setStatus(ErrorConverting); + LYXERR(Debug::GRAPHICS) + << "\tCould not create temporary file." << endl; + return; + } + filename = unzipFile(filename_, unzipped_filename_.toFilesystemEncoding()); + } else + filename = filename_; + + docstring const displayed_filename = makeDisplayPath(filename_.absFilename()); + LYXERR(Debug::GRAPHICS) << "[graphics::CacheItem::Impl::convertToDisplayFormat]\n" + << "\tAttempting to convert image file: " << filename + << "\n\twith displayed filename: " << lyx::to_utf8(displayed_filename) + << endl; + + string const from = formats.getFormatFromFile(filename); + if (from.empty()) { + setStatus(ErrorConverting); + LYXERR(Debug::GRAPHICS) + << "\tCould not determine file format." << endl; + } + LYXERR(Debug::GRAPHICS) + << "\n\tThe file contains " << from << " format data." << endl; + to_ = findTargetFormat(from); + + if (from == to_) { + // No conversion needed! + LYXERR(Debug::GRAPHICS) << "\tNo conversion needed (from == to)!" << endl; + file_to_load_ = filename; + loadImage(); + return; + } + + if (ConverterCache::get().inCache(filename, to_)) { + LYXERR(Debug::GRAPHICS) << "\tNo conversion needed (file in file cache)!" + << endl; + file_to_load_ = ConverterCache::get().cacheName(filename, to_); + loadImage(); + return; + } + + LYXERR(Debug::GRAPHICS) << "\tConverting it to " << to_ << " format." << endl; + + // Add some stuff to create a uniquely named temporary file. + // This file is deleted in loadImage after it is loaded into memory. + FileName const to_file_base(tempName(FileName(), "CacheItem")); + remove_loaded_file_ = true; + + // Remove the temp file, we only want the name... + // FIXME: This is unsafe! + unlink(to_file_base); + + // Connect a signal to this->imageConverted and pass this signal to + // the graphics converter so that we can load the modified file + // on completion of the conversion process. + converter_.reset(new Converter(filename, to_file_base.absFilename(), from, to_)); + converter_->connect(boost::bind(&Impl::imageConverted, this, _1)); + converter_->startConversion(); +} + +} // namespace graphics +} // namespace lyx diff --git a/src/graphics/GraphicsConverter.C b/src/graphics/GraphicsConverter.C deleted file mode 100644 index 3a69da9bdc..0000000000 --- a/src/graphics/GraphicsConverter.C +++ /dev/null @@ -1,404 +0,0 @@ -/** - * \file GraphicsConverter.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Angus Leeming - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "GraphicsConverter.h" - -#include "converter.h" -#include "debug.h" -#include "format.h" - -#include "support/filetools.h" -#include "support/forkedcallqueue.h" -#include "support/convert.h" -#include "support/lstrings.h" -#include "support/lyxlib.h" -#include "support/os.h" - -#include - -#include -#include - -namespace support = lyx::support; - -using support::addExtension; -using support::changeExtension; -using support::FileName; -using support::Forkedcall; -using support::ForkedCallQueue; -using support::getExtension; -using support::libScriptSearch; -using support::onlyPath; -using support::onlyFilename; -using support::quoteName; -using support::quote_python; -using support::subst; -using support::tempName; -using support::unlink; - -using std::endl; -using std::ostream; -using std::ostringstream; -using std::string; - - -namespace lyx { -namespace graphics { - -class Converter::Impl : public boost::signals::trackable { -public: - /// - Impl(FileName const &, string const &, string const &, string const &); - - /// - void startConversion(); - - /** This method is connected to a signal passed to the forked call - * class, passing control back here when the conversion is completed. - * Cleans-up the temporary files, emits the finishedConversion - * signal and removes the Converter from the list of all processes. - */ - void converted(pid_t pid, int retval); - - /** At the end of the conversion process inform the outside world - * by emitting a signal. - */ - typedef boost::signal SignalType; - /// - SignalType finishedConversion; - - /// - string script_command_; - /// - FileName script_file_; - /// - FileName to_file_; - /// - bool valid_process_; - /// - bool finished_; -}; - - -bool Converter::isReachable(string const & from_format_name, - string const & to_format_name) -{ - return theConverters().isReachable(from_format_name, to_format_name); -} - - -Converter::Converter(FileName const & from_file, string const & to_file_base, - string const & from_format, string const & to_format) - : pimpl_(new Impl(from_file, to_file_base, from_format, to_format)) -{} - - -// Empty d-tor out-of-line to keep boost::scoped_ptr happy. -Converter::~Converter() -{} - - -void Converter::startConversion() const -{ - pimpl_->startConversion(); -} - - -boost::signals::connection Converter::connect(slot_type const & slot) const -{ - return pimpl_->finishedConversion.connect(slot); -} - - -FileName const & Converter::convertedFile() const -{ - static FileName const empty; - return pimpl_->finished_ ? pimpl_->to_file_ : empty; -} - -/** Build the conversion script. - * The script is output to the stream \p script. - */ -static void build_script(FileName const & from_file, string const & to_file_base, - string const & from_format, string const & to_format, - ostream & script); - - -Converter::Impl::Impl(FileName const & from_file, string const & to_file_base, - string const & from_format, string const & to_format) - : valid_process_(false), finished_(false) -{ - LYXERR(Debug::GRAPHICS) << "Converter c-tor:\n" - << "\tfrom_file: " << from_file - << "\n\tto_file_base: " << to_file_base - << "\n\tfrom_format: " << from_format - << "\n\tto_format: " << to_format << endl; - - // The converted image is to be stored in this file (we do not - // use ChangeExtension because this is a basename which may - // nevertheless contain a '.') - to_file_ = FileName(to_file_base + '.' + formats.extension(to_format)); - - // The conversion commands are stored in a stringstream - ostringstream script; - build_script(from_file, to_file_base, from_format, to_format, script); - LYXERR(Debug::GRAPHICS) << "\tConversion script:" - << "\n--------------------------------------\n" - << script.str() - << "\n--------------------------------------\n"; - - // Output the script to file. - static int counter = 0; - script_file_ = FileName(onlyPath(to_file_base) + "lyxconvert" + - convert(counter++) + ".py"); - - std::ofstream fs(script_file_.toFilesystemEncoding().c_str()); - if (!fs.good()) { - lyxerr << "Unable to write the conversion script to \"" - << script_file_ << '\n' - << "Please check your directory permissions." - << std::endl; - return; - } - - fs << script.str(); - fs.close(); - - // The command needed to run the conversion process - // We create a dummy command for ease of understanding of the - // list of forked processes. - // Note: 'python ' is absolutely essential, or execvp will fail. - script_command_ = support::os::python() + ' ' + - quoteName(script_file_.toFilesystemEncoding()) + ' ' + - quoteName(onlyFilename(from_file.toFilesystemEncoding())) + ' ' + - quoteName(to_format); - // All is ready to go - valid_process_ = true; -} - - -void Converter::Impl::startConversion() -{ - if (!valid_process_) { - converted(0, 1); - return; - } - - Forkedcall::SignalTypePtr - ptr = ForkedCallQueue::get().add(script_command_); - - ptr->connect(boost::bind(&Impl::converted, this, _1, _2)); - -} - -void Converter::Impl::converted(pid_t /* pid */, int retval) -{ - if (finished_) - // We're done already! - return; - - finished_ = true; - // Clean-up behind ourselves - unlink(script_file_); - - if (retval > 0) { - unlink(to_file_); - to_file_.erase(); - finishedConversion(false); - } else { - finishedConversion(true); - } -} - - -static string const move_file(string const & from_file, string const & to_file) -{ - if (from_file == to_file) - return string(); - - ostringstream command; - command << "fromfile = " << from_file << "\n" - << "tofile = " << to_file << "\n\n" - << "try:\n" - << " os.rename(fromfile, tofile)\n" - << "except:\n" - << " try:\n" - << " shutil.copy(fromfile, tofile)\n" - << " except:\n" - << " sys.exit(1)\n" - << " unlinkNoThrow(fromfile)\n"; - - return command.str(); -} - - -static void build_conversion_command(string const & command, ostream & script) -{ - // Store in the python script - script << "\nif os.system(r'" << command << "') != 0:\n"; - - // Test that this was successful. If not, remove - // ${outfile} and exit the python script - script << " unlinkNoThrow(outfile)\n" - << " sys.exit(1)\n\n"; - - // Test that the outfile exists. - // ImageMagick's convert will often create ${outfile}.0, - // ${outfile}.1. - // If this occurs, move ${outfile}.0 to ${outfile} - // and delete ${outfile}.? (ignore errors) - script << "if not os.path.isfile(outfile):\n" - " if os.path.isfile(outfile + '.0'):\n" - " os.rename(outfile + '.0', outfile)\n" - " import glob\n" - " for file in glob.glob(outfile + '.?'):\n" - " unlinkNoThrow(file)\n" - " else:\n" - " sys.exit(1)\n\n"; - - // Delete the infile - script << "unlinkNoThrow(infile)\n\n"; -} - - -static void build_script(FileName const & from_file, - string const & to_file_base, - string const & from_format, - string const & to_format, - ostream & script) -{ - BOOST_ASSERT(from_format != to_format); - LYXERR(Debug::GRAPHICS) << "build_script ... "; - typedef Converters::EdgePath EdgePath; - - script << "#!/usr/bin/env python\n" - "# -*- coding: utf-8 -*-\n" - "import os, shutil, sys, locale\n\n" - "def unlinkNoThrow(file):\n" - " ''' remove a file, do not throw if an error occurs '''\n" - " try:\n" - " os.unlink(file)\n" - " except:\n" - " pass\n\n" - "def utf8ToDefaultEncoding(file):\n" - " ''' if possible, convert to the default encoding '''\n" - " try:\n" - " language, output_encoding = locale.getdefaultlocale()\n" - " if output_encoding == None:\n" - " output_encoding = 'latin1'\n" - " return unicode(file, 'utf8').encode(output_encoding)\n" - " except:\n" - " return file\n\n"; - - // we do not use ChangeExtension because this is a basename - // which may nevertheless contain a '.' - string const to_file = to_file_base + '.' - + formats.extension(to_format); - - EdgePath const edgepath = from_format.empty() ? - EdgePath() : - theConverters().getPath(from_format, to_format); - - // Create a temporary base file-name for all intermediate steps. - // Remember to remove the temp file because we only want the name... - static int counter = 0; - string const tmp = "gconvert" + convert(counter++); - FileName const to_base(tempName(FileName(), tmp)); - unlink(to_base); - - // Create a copy of the file in case the original name contains - // problematic characters like ' or ". We can work around that problem - // in python, but the converters might be shell scripts and have more - // troubles with it. - string outfile = addExtension(to_base.absFilename(), getExtension(from_file.absFilename())); - script << "infile = utf8ToDefaultEncoding(" - << quoteName(from_file.absFilename(), quote_python) - << ")\n" - "outfile = " << quoteName(outfile, quote_python) << "\n" - "shutil.copy(infile, outfile)\n"; - - // Some converters (e.g. lilypond) can only output files to the - // current directory, so we need to change the current directory. - // This has the added benefit that all other files that may be - // generated by the converter are deleted when LyX closes and do not - // clutter the real working directory. - script << "os.chdir(" << quoteName(onlyPath(outfile)) << ")\n"; - - if (edgepath.empty()) { - // Either from_format is unknown or we don't have a - // converter path from from_format to to_format, so we use - // the default converter. - script << "infile = outfile\n" - << "outfile = " << quoteName(to_file, quote_python) - << '\n'; - - ostringstream os; - os << support::os::python() << ' ' - << libScriptSearch("$$s/scripts/convertDefault.py", - quote_python) << ' '; - if (!from_format.empty()) - os << from_format << ':'; - // The extra " quotes around infile and outfile are needed - // because the filename may contain spaces and it is used - // as argument of os.system(). - os << "' + '\"' + infile + '\"' + ' " - << to_format << ":' + '\"' + outfile + '\"' + '"; - string const command = os.str(); - - LYXERR(Debug::GRAPHICS) - << "\tNo converter defined! I use convertDefault.py\n\t" - << command << endl; - - build_conversion_command(command, script); - } - - // The conversion commands may contain these tokens that need to be - // changed to infile, infile_base, outfile respectively. - string const token_from("$$i"); - string const token_base("$$b"); - string const token_to("$$o"); - - EdgePath::const_iterator it = edgepath.begin(); - EdgePath::const_iterator end = edgepath.end(); - - for (; it != end; ++it) { - lyx::Converter const & conv = theConverters().get(*it); - - // Build the conversion command - string const infile = outfile; - string const infile_base = changeExtension(infile, string()); - outfile = addExtension(to_base.absFilename(), conv.To->extension()); - - // Store these names in the python script - script << "infile = " << quoteName(infile, quote_python) << "\n" - "infile_base = " << quoteName(infile_base, quote_python) << "\n" - "outfile = " << quoteName(outfile, quote_python) << '\n'; - - // See comment about extra " quotes above (although that - // applies only for the first loop run here). - string command = conv.command; - command = subst(command, token_from, "' + '\"' + infile + '\"' + '"); - command = subst(command, token_base, "' + '\"' + infile_base + '\"' + '"); - command = subst(command, token_to, "' + '\"' + outfile + '\"' + '"); - command = libScriptSearch(command, quote_python); - - build_conversion_command(command, script); - } - - // Move the final outfile to to_file - script << move_file("outfile", quoteName(to_file, quote_python)); - LYXERR(Debug::GRAPHICS) << "ready!" << endl; -} - -} // namespace graphics - -} // namespace lyx diff --git a/src/graphics/GraphicsConverter.cpp b/src/graphics/GraphicsConverter.cpp new file mode 100644 index 0000000000..3a69da9bdc --- /dev/null +++ b/src/graphics/GraphicsConverter.cpp @@ -0,0 +1,404 @@ +/** + * \file GraphicsConverter.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Angus Leeming + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "GraphicsConverter.h" + +#include "converter.h" +#include "debug.h" +#include "format.h" + +#include "support/filetools.h" +#include "support/forkedcallqueue.h" +#include "support/convert.h" +#include "support/lstrings.h" +#include "support/lyxlib.h" +#include "support/os.h" + +#include + +#include +#include + +namespace support = lyx::support; + +using support::addExtension; +using support::changeExtension; +using support::FileName; +using support::Forkedcall; +using support::ForkedCallQueue; +using support::getExtension; +using support::libScriptSearch; +using support::onlyPath; +using support::onlyFilename; +using support::quoteName; +using support::quote_python; +using support::subst; +using support::tempName; +using support::unlink; + +using std::endl; +using std::ostream; +using std::ostringstream; +using std::string; + + +namespace lyx { +namespace graphics { + +class Converter::Impl : public boost::signals::trackable { +public: + /// + Impl(FileName const &, string const &, string const &, string const &); + + /// + void startConversion(); + + /** This method is connected to a signal passed to the forked call + * class, passing control back here when the conversion is completed. + * Cleans-up the temporary files, emits the finishedConversion + * signal and removes the Converter from the list of all processes. + */ + void converted(pid_t pid, int retval); + + /** At the end of the conversion process inform the outside world + * by emitting a signal. + */ + typedef boost::signal SignalType; + /// + SignalType finishedConversion; + + /// + string script_command_; + /// + FileName script_file_; + /// + FileName to_file_; + /// + bool valid_process_; + /// + bool finished_; +}; + + +bool Converter::isReachable(string const & from_format_name, + string const & to_format_name) +{ + return theConverters().isReachable(from_format_name, to_format_name); +} + + +Converter::Converter(FileName const & from_file, string const & to_file_base, + string const & from_format, string const & to_format) + : pimpl_(new Impl(from_file, to_file_base, from_format, to_format)) +{} + + +// Empty d-tor out-of-line to keep boost::scoped_ptr happy. +Converter::~Converter() +{} + + +void Converter::startConversion() const +{ + pimpl_->startConversion(); +} + + +boost::signals::connection Converter::connect(slot_type const & slot) const +{ + return pimpl_->finishedConversion.connect(slot); +} + + +FileName const & Converter::convertedFile() const +{ + static FileName const empty; + return pimpl_->finished_ ? pimpl_->to_file_ : empty; +} + +/** Build the conversion script. + * The script is output to the stream \p script. + */ +static void build_script(FileName const & from_file, string const & to_file_base, + string const & from_format, string const & to_format, + ostream & script); + + +Converter::Impl::Impl(FileName const & from_file, string const & to_file_base, + string const & from_format, string const & to_format) + : valid_process_(false), finished_(false) +{ + LYXERR(Debug::GRAPHICS) << "Converter c-tor:\n" + << "\tfrom_file: " << from_file + << "\n\tto_file_base: " << to_file_base + << "\n\tfrom_format: " << from_format + << "\n\tto_format: " << to_format << endl; + + // The converted image is to be stored in this file (we do not + // use ChangeExtension because this is a basename which may + // nevertheless contain a '.') + to_file_ = FileName(to_file_base + '.' + formats.extension(to_format)); + + // The conversion commands are stored in a stringstream + ostringstream script; + build_script(from_file, to_file_base, from_format, to_format, script); + LYXERR(Debug::GRAPHICS) << "\tConversion script:" + << "\n--------------------------------------\n" + << script.str() + << "\n--------------------------------------\n"; + + // Output the script to file. + static int counter = 0; + script_file_ = FileName(onlyPath(to_file_base) + "lyxconvert" + + convert(counter++) + ".py"); + + std::ofstream fs(script_file_.toFilesystemEncoding().c_str()); + if (!fs.good()) { + lyxerr << "Unable to write the conversion script to \"" + << script_file_ << '\n' + << "Please check your directory permissions." + << std::endl; + return; + } + + fs << script.str(); + fs.close(); + + // The command needed to run the conversion process + // We create a dummy command for ease of understanding of the + // list of forked processes. + // Note: 'python ' is absolutely essential, or execvp will fail. + script_command_ = support::os::python() + ' ' + + quoteName(script_file_.toFilesystemEncoding()) + ' ' + + quoteName(onlyFilename(from_file.toFilesystemEncoding())) + ' ' + + quoteName(to_format); + // All is ready to go + valid_process_ = true; +} + + +void Converter::Impl::startConversion() +{ + if (!valid_process_) { + converted(0, 1); + return; + } + + Forkedcall::SignalTypePtr + ptr = ForkedCallQueue::get().add(script_command_); + + ptr->connect(boost::bind(&Impl::converted, this, _1, _2)); + +} + +void Converter::Impl::converted(pid_t /* pid */, int retval) +{ + if (finished_) + // We're done already! + return; + + finished_ = true; + // Clean-up behind ourselves + unlink(script_file_); + + if (retval > 0) { + unlink(to_file_); + to_file_.erase(); + finishedConversion(false); + } else { + finishedConversion(true); + } +} + + +static string const move_file(string const & from_file, string const & to_file) +{ + if (from_file == to_file) + return string(); + + ostringstream command; + command << "fromfile = " << from_file << "\n" + << "tofile = " << to_file << "\n\n" + << "try:\n" + << " os.rename(fromfile, tofile)\n" + << "except:\n" + << " try:\n" + << " shutil.copy(fromfile, tofile)\n" + << " except:\n" + << " sys.exit(1)\n" + << " unlinkNoThrow(fromfile)\n"; + + return command.str(); +} + + +static void build_conversion_command(string const & command, ostream & script) +{ + // Store in the python script + script << "\nif os.system(r'" << command << "') != 0:\n"; + + // Test that this was successful. If not, remove + // ${outfile} and exit the python script + script << " unlinkNoThrow(outfile)\n" + << " sys.exit(1)\n\n"; + + // Test that the outfile exists. + // ImageMagick's convert will often create ${outfile}.0, + // ${outfile}.1. + // If this occurs, move ${outfile}.0 to ${outfile} + // and delete ${outfile}.? (ignore errors) + script << "if not os.path.isfile(outfile):\n" + " if os.path.isfile(outfile + '.0'):\n" + " os.rename(outfile + '.0', outfile)\n" + " import glob\n" + " for file in glob.glob(outfile + '.?'):\n" + " unlinkNoThrow(file)\n" + " else:\n" + " sys.exit(1)\n\n"; + + // Delete the infile + script << "unlinkNoThrow(infile)\n\n"; +} + + +static void build_script(FileName const & from_file, + string const & to_file_base, + string const & from_format, + string const & to_format, + ostream & script) +{ + BOOST_ASSERT(from_format != to_format); + LYXERR(Debug::GRAPHICS) << "build_script ... "; + typedef Converters::EdgePath EdgePath; + + script << "#!/usr/bin/env python\n" + "# -*- coding: utf-8 -*-\n" + "import os, shutil, sys, locale\n\n" + "def unlinkNoThrow(file):\n" + " ''' remove a file, do not throw if an error occurs '''\n" + " try:\n" + " os.unlink(file)\n" + " except:\n" + " pass\n\n" + "def utf8ToDefaultEncoding(file):\n" + " ''' if possible, convert to the default encoding '''\n" + " try:\n" + " language, output_encoding = locale.getdefaultlocale()\n" + " if output_encoding == None:\n" + " output_encoding = 'latin1'\n" + " return unicode(file, 'utf8').encode(output_encoding)\n" + " except:\n" + " return file\n\n"; + + // we do not use ChangeExtension because this is a basename + // which may nevertheless contain a '.' + string const to_file = to_file_base + '.' + + formats.extension(to_format); + + EdgePath const edgepath = from_format.empty() ? + EdgePath() : + theConverters().getPath(from_format, to_format); + + // Create a temporary base file-name for all intermediate steps. + // Remember to remove the temp file because we only want the name... + static int counter = 0; + string const tmp = "gconvert" + convert(counter++); + FileName const to_base(tempName(FileName(), tmp)); + unlink(to_base); + + // Create a copy of the file in case the original name contains + // problematic characters like ' or ". We can work around that problem + // in python, but the converters might be shell scripts and have more + // troubles with it. + string outfile = addExtension(to_base.absFilename(), getExtension(from_file.absFilename())); + script << "infile = utf8ToDefaultEncoding(" + << quoteName(from_file.absFilename(), quote_python) + << ")\n" + "outfile = " << quoteName(outfile, quote_python) << "\n" + "shutil.copy(infile, outfile)\n"; + + // Some converters (e.g. lilypond) can only output files to the + // current directory, so we need to change the current directory. + // This has the added benefit that all other files that may be + // generated by the converter are deleted when LyX closes and do not + // clutter the real working directory. + script << "os.chdir(" << quoteName(onlyPath(outfile)) << ")\n"; + + if (edgepath.empty()) { + // Either from_format is unknown or we don't have a + // converter path from from_format to to_format, so we use + // the default converter. + script << "infile = outfile\n" + << "outfile = " << quoteName(to_file, quote_python) + << '\n'; + + ostringstream os; + os << support::os::python() << ' ' + << libScriptSearch("$$s/scripts/convertDefault.py", + quote_python) << ' '; + if (!from_format.empty()) + os << from_format << ':'; + // The extra " quotes around infile and outfile are needed + // because the filename may contain spaces and it is used + // as argument of os.system(). + os << "' + '\"' + infile + '\"' + ' " + << to_format << ":' + '\"' + outfile + '\"' + '"; + string const command = os.str(); + + LYXERR(Debug::GRAPHICS) + << "\tNo converter defined! I use convertDefault.py\n\t" + << command << endl; + + build_conversion_command(command, script); + } + + // The conversion commands may contain these tokens that need to be + // changed to infile, infile_base, outfile respectively. + string const token_from("$$i"); + string const token_base("$$b"); + string const token_to("$$o"); + + EdgePath::const_iterator it = edgepath.begin(); + EdgePath::const_iterator end = edgepath.end(); + + for (; it != end; ++it) { + lyx::Converter const & conv = theConverters().get(*it); + + // Build the conversion command + string const infile = outfile; + string const infile_base = changeExtension(infile, string()); + outfile = addExtension(to_base.absFilename(), conv.To->extension()); + + // Store these names in the python script + script << "infile = " << quoteName(infile, quote_python) << "\n" + "infile_base = " << quoteName(infile_base, quote_python) << "\n" + "outfile = " << quoteName(outfile, quote_python) << '\n'; + + // See comment about extra " quotes above (although that + // applies only for the first loop run here). + string command = conv.command; + command = subst(command, token_from, "' + '\"' + infile + '\"' + '"); + command = subst(command, token_base, "' + '\"' + infile_base + '\"' + '"); + command = subst(command, token_to, "' + '\"' + outfile + '\"' + '"); + command = libScriptSearch(command, quote_python); + + build_conversion_command(command, script); + } + + // Move the final outfile to to_file + script << move_file("outfile", quoteName(to_file, quote_python)); + LYXERR(Debug::GRAPHICS) << "ready!" << endl; +} + +} // namespace graphics + +} // namespace lyx diff --git a/src/graphics/GraphicsImage.C b/src/graphics/GraphicsImage.C deleted file mode 100644 index c713040824..0000000000 --- a/src/graphics/GraphicsImage.C +++ /dev/null @@ -1,56 +0,0 @@ -/** - * \file GraphicsImage.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Baruch Even - * \author Angus Leeming - * \author Herbert Voß - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "GraphicsImage.h" -#include "GraphicsParams.h" -#include "debug.h" - - -namespace lyx { -namespace graphics { - -// This is to be connected to a function that will return a new -// instance of a viable derived class. -boost::function Image::newImage; - -/// Return the list of loadable formats. -boost::function Image::loadableFormats; - - -std::pair -Image::getScaledDimensions(Params const & params) const -{ - // scale only when value > 0 - unsigned int width; - unsigned int height; - if (params.scale) { - width = (getWidth() * params.scale) / 100; - height = (getHeight() * params.scale) / 100; - } else { - width = getWidth(); - height = getHeight(); - } - - LYXERR(Debug::GRAPHICS) - << "graphics::Image::getScaledDimensions()" - << "\n\tparams.scale : " << params.scale - << "\n\twidth : " << width - << "\n\theight : " << height - << std::endl; - - return std::make_pair(width, height); -} - -} // namespace graphics -} // namespace lyx diff --git a/src/graphics/GraphicsImage.cpp b/src/graphics/GraphicsImage.cpp new file mode 100644 index 0000000000..c713040824 --- /dev/null +++ b/src/graphics/GraphicsImage.cpp @@ -0,0 +1,56 @@ +/** + * \file GraphicsImage.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Baruch Even + * \author Angus Leeming + * \author Herbert Voß + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "GraphicsImage.h" +#include "GraphicsParams.h" +#include "debug.h" + + +namespace lyx { +namespace graphics { + +// This is to be connected to a function that will return a new +// instance of a viable derived class. +boost::function Image::newImage; + +/// Return the list of loadable formats. +boost::function Image::loadableFormats; + + +std::pair +Image::getScaledDimensions(Params const & params) const +{ + // scale only when value > 0 + unsigned int width; + unsigned int height; + if (params.scale) { + width = (getWidth() * params.scale) / 100; + height = (getHeight() * params.scale) / 100; + } else { + width = getWidth(); + height = getHeight(); + } + + LYXERR(Debug::GRAPHICS) + << "graphics::Image::getScaledDimensions()" + << "\n\tparams.scale : " << params.scale + << "\n\twidth : " << width + << "\n\theight : " << height + << std::endl; + + return std::make_pair(width, height); +} + +} // namespace graphics +} // namespace lyx diff --git a/src/graphics/GraphicsLoader.C b/src/graphics/GraphicsLoader.C deleted file mode 100644 index d7627481f6..0000000000 --- a/src/graphics/GraphicsLoader.C +++ /dev/null @@ -1,302 +0,0 @@ -/** - * \file GraphicsLoader.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Angus Leeming - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "GraphicsLoader.h" - -#include "GraphicsCacheItem.h" -#include "GraphicsImage.h" -#include "GraphicsParams.h" -#include "LoaderQueue.h" - -#include - - -using std::string; - - -namespace lyx { - -using support::FileName; - -namespace graphics { - -class Loader::Impl : public boost::signals::trackable { -public: - /// - Impl(); - /// - ~Impl(); - /// - void resetFile(FileName const &); - /// - void resetParams(Params const &); - /// - void createPixmap(); - /// - void startLoading(); - /// - Params const & params() const { return params_; } - - /// The loading status of the image. - ImageStatus status_; - /** Must store a copy of the cached item to ensure that it is not - * erased unexpectedly by the cache itself. - */ - Cache::ItemPtr cached_item_; - /// We modify a local copy of the image once it is loaded. - Image::ImagePtr image_; - /// This signal is emitted when the image loading status changes. - boost::signal signal_; - -private: - /// - void statusChanged(); - /// - void checkedLoading(); - - /// - Params params_; -}; - - -Loader::Loader() - : pimpl_(new Impl) -{} - - -Loader::Loader(FileName const & file, DisplayType type) - : pimpl_(new Impl) -{ - reset(file, type); -} - - -Loader::Loader(FileName const & file, Params const & params) - : pimpl_(new Impl) -{ - reset(file, params); -} - - -Loader::Loader(Loader const & other) - : pimpl_(new Impl) -{ - Params const & params = other.pimpl_->params(); - reset(params.filename, params); -} - - -Loader::~Loader() -{} - - -Loader & Loader::operator=(Loader const & other) -{ - if (this != &other) { - Params const & params = other.pimpl_->params(); - reset(params.filename, params); - } - return *this; -} - - -void Loader::reset(FileName const & file, DisplayType type) const -{ - Params params; - params.display = type; - pimpl_->resetParams(params); - - pimpl_->resetFile(file); - pimpl_->createPixmap(); -} - - -void Loader::reset(FileName const & file, Params const & params) const -{ - pimpl_->resetParams(params); - pimpl_->resetFile(file); - pimpl_->createPixmap(); -} - - -void Loader::reset(Params const & params) const -{ - pimpl_->resetParams(params); - pimpl_->createPixmap(); -} - - -void Loader::startLoading() const -{ - if (pimpl_->status_ != WaitingToLoad || !pimpl_->cached_item_.get()) - return; - pimpl_->startLoading(); -} - - -void Loader::startMonitoring() const -{ - if (!pimpl_->cached_item_.get()) - return; - - pimpl_->cached_item_->startMonitoring(); -} - - -bool Loader::monitoring() const -{ - if (!pimpl_->cached_item_.get()) - return false; - - return pimpl_->cached_item_->monitoring(); -} - - -unsigned long Loader::checksum() const -{ - if (!pimpl_->cached_item_.get()) - return 0; - - return pimpl_->cached_item_->checksum(); -} - - -FileName const & Loader::filename() const -{ - static FileName const empty; - return pimpl_->cached_item_.get() ? - pimpl_->cached_item_->filename() : empty; -} - - -ImageStatus Loader::status() const -{ - return pimpl_->status_; -} - - -boost::signals::connection Loader::connect(slot_type const & slot) const -{ - return pimpl_->signal_.connect(slot); -} - - -Image const * Loader::image() const -{ - return pimpl_->image_.get(); -} - - -Loader::Impl::Impl() - : status_(WaitingToLoad) -{ -} - - -Loader::Impl::~Impl() -{ - resetFile(FileName()); -} - - -void Loader::Impl::resetFile(FileName const & file) -{ - FileName const old_file = cached_item_.get() ? - cached_item_->filename() : FileName(); - - if (file == old_file) - return; - - // If monitoring() the current file, should continue to monitor the - // new file. - bool continue_monitoring = false; - - if (!old_file.empty()) { - continue_monitoring = cached_item_->monitoring(); - cached_item_.reset(); - Cache::get().remove(old_file); - } - - status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad; - image_.reset(); - - if (cached_item_.get() || file.empty()) - return; - - Cache & gc = Cache::get(); - if (!gc.inCache(file)) - gc.add(file); - - // We /must/ make a local copy of this. - cached_item_ = gc.item(file); - status_ = cached_item_->status(); - - if (continue_monitoring && !cached_item_->monitoring()) - cached_item_->startMonitoring(); - - cached_item_->connect(boost::bind(&Impl::statusChanged, this)); -} - - -void Loader::Impl::resetParams(Params const & params) -{ - if (params == params_) - return; - - params_ = params; - status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad; - image_.reset(); -} - - -void Loader::Impl::statusChanged() -{ - status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad; - createPixmap(); - signal_(); -} - - -void Loader::Impl::createPixmap() -{ - if (!cached_item_.get() || - params_.display == NoDisplay || status_ != Loaded) - return; - - image_.reset(cached_item_->image()->clone()); - - // These do nothing if there's nothing to do - image_->clip(params_); - image_->rotate(params_); - image_->scale(params_); - - bool const success = image_->setPixmap(params_); - - if (success) { - status_ = Ready; - } else { - image_.reset(); - status_ = ErrorGeneratingPixmap; - } -} - -void Loader::Impl::startLoading() -{ - if (status_ != WaitingToLoad) - return; - - LoaderQueue::get().touch(cached_item_); -} - - -} // namespace graphics -} // namespace lyx diff --git a/src/graphics/GraphicsLoader.cpp b/src/graphics/GraphicsLoader.cpp new file mode 100644 index 0000000000..d7627481f6 --- /dev/null +++ b/src/graphics/GraphicsLoader.cpp @@ -0,0 +1,302 @@ +/** + * \file GraphicsLoader.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Angus Leeming + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "GraphicsLoader.h" + +#include "GraphicsCacheItem.h" +#include "GraphicsImage.h" +#include "GraphicsParams.h" +#include "LoaderQueue.h" + +#include + + +using std::string; + + +namespace lyx { + +using support::FileName; + +namespace graphics { + +class Loader::Impl : public boost::signals::trackable { +public: + /// + Impl(); + /// + ~Impl(); + /// + void resetFile(FileName const &); + /// + void resetParams(Params const &); + /// + void createPixmap(); + /// + void startLoading(); + /// + Params const & params() const { return params_; } + + /// The loading status of the image. + ImageStatus status_; + /** Must store a copy of the cached item to ensure that it is not + * erased unexpectedly by the cache itself. + */ + Cache::ItemPtr cached_item_; + /// We modify a local copy of the image once it is loaded. + Image::ImagePtr image_; + /// This signal is emitted when the image loading status changes. + boost::signal signal_; + +private: + /// + void statusChanged(); + /// + void checkedLoading(); + + /// + Params params_; +}; + + +Loader::Loader() + : pimpl_(new Impl) +{} + + +Loader::Loader(FileName const & file, DisplayType type) + : pimpl_(new Impl) +{ + reset(file, type); +} + + +Loader::Loader(FileName const & file, Params const & params) + : pimpl_(new Impl) +{ + reset(file, params); +} + + +Loader::Loader(Loader const & other) + : pimpl_(new Impl) +{ + Params const & params = other.pimpl_->params(); + reset(params.filename, params); +} + + +Loader::~Loader() +{} + + +Loader & Loader::operator=(Loader const & other) +{ + if (this != &other) { + Params const & params = other.pimpl_->params(); + reset(params.filename, params); + } + return *this; +} + + +void Loader::reset(FileName const & file, DisplayType type) const +{ + Params params; + params.display = type; + pimpl_->resetParams(params); + + pimpl_->resetFile(file); + pimpl_->createPixmap(); +} + + +void Loader::reset(FileName const & file, Params const & params) const +{ + pimpl_->resetParams(params); + pimpl_->resetFile(file); + pimpl_->createPixmap(); +} + + +void Loader::reset(Params const & params) const +{ + pimpl_->resetParams(params); + pimpl_->createPixmap(); +} + + +void Loader::startLoading() const +{ + if (pimpl_->status_ != WaitingToLoad || !pimpl_->cached_item_.get()) + return; + pimpl_->startLoading(); +} + + +void Loader::startMonitoring() const +{ + if (!pimpl_->cached_item_.get()) + return; + + pimpl_->cached_item_->startMonitoring(); +} + + +bool Loader::monitoring() const +{ + if (!pimpl_->cached_item_.get()) + return false; + + return pimpl_->cached_item_->monitoring(); +} + + +unsigned long Loader::checksum() const +{ + if (!pimpl_->cached_item_.get()) + return 0; + + return pimpl_->cached_item_->checksum(); +} + + +FileName const & Loader::filename() const +{ + static FileName const empty; + return pimpl_->cached_item_.get() ? + pimpl_->cached_item_->filename() : empty; +} + + +ImageStatus Loader::status() const +{ + return pimpl_->status_; +} + + +boost::signals::connection Loader::connect(slot_type const & slot) const +{ + return pimpl_->signal_.connect(slot); +} + + +Image const * Loader::image() const +{ + return pimpl_->image_.get(); +} + + +Loader::Impl::Impl() + : status_(WaitingToLoad) +{ +} + + +Loader::Impl::~Impl() +{ + resetFile(FileName()); +} + + +void Loader::Impl::resetFile(FileName const & file) +{ + FileName const old_file = cached_item_.get() ? + cached_item_->filename() : FileName(); + + if (file == old_file) + return; + + // If monitoring() the current file, should continue to monitor the + // new file. + bool continue_monitoring = false; + + if (!old_file.empty()) { + continue_monitoring = cached_item_->monitoring(); + cached_item_.reset(); + Cache::get().remove(old_file); + } + + status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad; + image_.reset(); + + if (cached_item_.get() || file.empty()) + return; + + Cache & gc = Cache::get(); + if (!gc.inCache(file)) + gc.add(file); + + // We /must/ make a local copy of this. + cached_item_ = gc.item(file); + status_ = cached_item_->status(); + + if (continue_monitoring && !cached_item_->monitoring()) + cached_item_->startMonitoring(); + + cached_item_->connect(boost::bind(&Impl::statusChanged, this)); +} + + +void Loader::Impl::resetParams(Params const & params) +{ + if (params == params_) + return; + + params_ = params; + status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad; + image_.reset(); +} + + +void Loader::Impl::statusChanged() +{ + status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad; + createPixmap(); + signal_(); +} + + +void Loader::Impl::createPixmap() +{ + if (!cached_item_.get() || + params_.display == NoDisplay || status_ != Loaded) + return; + + image_.reset(cached_item_->image()->clone()); + + // These do nothing if there's nothing to do + image_->clip(params_); + image_->rotate(params_); + image_->scale(params_); + + bool const success = image_->setPixmap(params_); + + if (success) { + status_ = Ready; + } else { + image_.reset(); + status_ = ErrorGeneratingPixmap; + } +} + +void Loader::Impl::startLoading() +{ + if (status_ != WaitingToLoad) + return; + + LoaderQueue::get().touch(cached_item_); +} + + +} // namespace graphics +} // namespace lyx diff --git a/src/graphics/GraphicsParams.C b/src/graphics/GraphicsParams.C deleted file mode 100644 index d13dc1800f..0000000000 --- a/src/graphics/GraphicsParams.C +++ /dev/null @@ -1,110 +0,0 @@ -/** - * \file GraphicsParams.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Angus Leeming - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "GraphicsParams.h" - -#include "lyxlength.h" - -#include - - -using std::string; -using std::abs; - - -namespace lyx { -namespace graphics { - -Params::Params() - : display(ColorDisplay), - scale(100), - angle(0) -{} - - -bool operator==(Params const & a, Params const & b) -{ - return (a.filename == b.filename && - a.display == b.display && - a.bb == b.bb && - a.scale == b.scale && - a.angle == b.angle); -} - - -bool operator!=(Params const & a, Params const & b) -{ - return !(a == b); -} - - -std::ostream & operator<<(std::ostream & os, BoundingBox const & bb) -{ - os << bb.xl << ' ' << bb.yb << ' ' << bb.xr << ' ' << bb.yt; - return os; -} - - -BoundingBox::BoundingBox() - : xl(0), yb(0), xr(0), yt(0) -{} - - -BoundingBox::BoundingBox(string const & bb) - : xl(0), yb(0), xr(0), yt(0) -{ - if (bb.empty()) - return; - - std::istringstream is(bb.c_str()); - string a, b, c, d; - is >> a >> b >> c >> d; - - // inBP returns the length in Postscript points. - // Note further that there are 72 Postscript pixels per inch. - unsigned int const xl_tmp = abs(LyXLength(a).inBP()); - unsigned int const yb_tmp = abs(LyXLength(b).inBP()); - unsigned int const xr_tmp = abs(LyXLength(c).inBP()); - unsigned int const yt_tmp = abs(LyXLength(d).inBP()); - - if (xr_tmp <= xl_tmp || yt_tmp <= yb_tmp) - return; - - xl = xl_tmp; - yb = yb_tmp; - xr = xr_tmp; - yt = yt_tmp; -} - - -bool BoundingBox::empty() const -{ - return (!xl && !yb && !xr && !yt); -} - - -bool operator==(BoundingBox const & a, BoundingBox const & b) -{ - return (a.xl == b.xl && - a.yb == b.yb && - a.xr == b.xr && - a.yt == b.yt); -} - - -bool operator!=(BoundingBox const & a, BoundingBox const & b) -{ - return !(a == b); -} - -} // namespace graphics -} // namespace lyx diff --git a/src/graphics/GraphicsParams.cpp b/src/graphics/GraphicsParams.cpp new file mode 100644 index 0000000000..d13dc1800f --- /dev/null +++ b/src/graphics/GraphicsParams.cpp @@ -0,0 +1,110 @@ +/** + * \file GraphicsParams.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Angus Leeming + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "GraphicsParams.h" + +#include "lyxlength.h" + +#include + + +using std::string; +using std::abs; + + +namespace lyx { +namespace graphics { + +Params::Params() + : display(ColorDisplay), + scale(100), + angle(0) +{} + + +bool operator==(Params const & a, Params const & b) +{ + return (a.filename == b.filename && + a.display == b.display && + a.bb == b.bb && + a.scale == b.scale && + a.angle == b.angle); +} + + +bool operator!=(Params const & a, Params const & b) +{ + return !(a == b); +} + + +std::ostream & operator<<(std::ostream & os, BoundingBox const & bb) +{ + os << bb.xl << ' ' << bb.yb << ' ' << bb.xr << ' ' << bb.yt; + return os; +} + + +BoundingBox::BoundingBox() + : xl(0), yb(0), xr(0), yt(0) +{} + + +BoundingBox::BoundingBox(string const & bb) + : xl(0), yb(0), xr(0), yt(0) +{ + if (bb.empty()) + return; + + std::istringstream is(bb.c_str()); + string a, b, c, d; + is >> a >> b >> c >> d; + + // inBP returns the length in Postscript points. + // Note further that there are 72 Postscript pixels per inch. + unsigned int const xl_tmp = abs(LyXLength(a).inBP()); + unsigned int const yb_tmp = abs(LyXLength(b).inBP()); + unsigned int const xr_tmp = abs(LyXLength(c).inBP()); + unsigned int const yt_tmp = abs(LyXLength(d).inBP()); + + if (xr_tmp <= xl_tmp || yt_tmp <= yb_tmp) + return; + + xl = xl_tmp; + yb = yb_tmp; + xr = xr_tmp; + yt = yt_tmp; +} + + +bool BoundingBox::empty() const +{ + return (!xl && !yb && !xr && !yt); +} + + +bool operator==(BoundingBox const & a, BoundingBox const & b) +{ + return (a.xl == b.xl && + a.yb == b.yb && + a.xr == b.xr && + a.yt == b.yt); +} + + +bool operator!=(BoundingBox const & a, BoundingBox const & b) +{ + return !(a == b); +} + +} // namespace graphics +} // namespace lyx diff --git a/src/graphics/GraphicsTypes.C b/src/graphics/GraphicsTypes.C deleted file mode 100644 index f8f6f45a91..0000000000 --- a/src/graphics/GraphicsTypes.C +++ /dev/null @@ -1,49 +0,0 @@ -/** - * \file GraphicsTypes.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Rob Lahaye - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "graphics/GraphicsTypes.h" - -#include - -using std::string; - - -namespace lyx { -namespace graphics { - -namespace { - -/// The translator between the Display enum and corresponding lyx string. -Translator const initTranslator() -{ - Translator translator(DefaultDisplay, "default"); - - // Fill the display translator - translator.addPair(MonochromeDisplay, "monochrome"); - translator.addPair(GrayscaleDisplay, "grayscale"); - translator.addPair(ColorDisplay, "color"); - translator.addPair(NoDisplay, "none"); - - return translator; -} - -} // namespace anon - -Translator const & displayTranslator() -{ - static Translator const translator = - initTranslator(); - return translator; -} - -} // namespace graphics -} // namespace lyx diff --git a/src/graphics/GraphicsTypes.cpp b/src/graphics/GraphicsTypes.cpp new file mode 100644 index 0000000000..f8f6f45a91 --- /dev/null +++ b/src/graphics/GraphicsTypes.cpp @@ -0,0 +1,49 @@ +/** + * \file GraphicsTypes.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Rob Lahaye + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "graphics/GraphicsTypes.h" + +#include + +using std::string; + + +namespace lyx { +namespace graphics { + +namespace { + +/// The translator between the Display enum and corresponding lyx string. +Translator const initTranslator() +{ + Translator translator(DefaultDisplay, "default"); + + // Fill the display translator + translator.addPair(MonochromeDisplay, "monochrome"); + translator.addPair(GrayscaleDisplay, "grayscale"); + translator.addPair(ColorDisplay, "color"); + translator.addPair(NoDisplay, "none"); + + return translator; +} + +} // namespace anon + +Translator const & displayTranslator() +{ + static Translator const translator = + initTranslator(); + return translator; +} + +} // namespace graphics +} // namespace lyx diff --git a/src/graphics/LoaderQueue.C b/src/graphics/LoaderQueue.C deleted file mode 100644 index 6038dbe4b9..0000000000 --- a/src/graphics/LoaderQueue.C +++ /dev/null @@ -1,118 +0,0 @@ -/** - * \file LoaderQueue.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Alfredo Braunstein - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "LoaderQueue.h" -#include "GraphicsCacheItem.h" - -#include "debug.h" - -#include - -using std::endl; -using std::list; - -namespace lyx { -namespace graphics { - -int LoaderQueue::s_numimages_ = 5; -int LoaderQueue::s_millisecs_ = 500; - - -LoaderQueue & LoaderQueue::get() -{ - static LoaderQueue singleton; - return singleton; -} - - -void LoaderQueue::loadNext() -{ - LYXERR(Debug::GRAPHICS) << "LoaderQueue: " - << cache_queue_.size() - << " items in the queue" << endl; - int counter = s_numimages_; - while (cache_queue_.size() && counter--) { - Cache::ItemPtr ptr = cache_queue_.front(); - cache_set_.erase(ptr); - cache_queue_.pop_front(); - if (ptr->status() == WaitingToLoad) - ptr->startLoading(); - } - if (cache_queue_.size()) { - startLoader(); - } else { - stopLoader(); - } -} - - -void LoaderQueue::setPriority(int numimages , int millisecs) -{ - s_numimages_ = numimages; - s_millisecs_ = millisecs; - LYXERR(Debug::GRAPHICS) << "LoaderQueue: priority set to " - << s_numimages_ << " images at a time, " - << s_millisecs_ << " milliseconds between calls" - << endl; -} - - -LoaderQueue::LoaderQueue() : timer(s_millisecs_, Timeout::ONETIME), - running_(false) -{ - timer.timeout.connect(boost::bind(&LoaderQueue::loadNext, this)); -} - - -void LoaderQueue::startLoader() -{ - LYXERR(Debug::GRAPHICS) << "LoaderQueue: waking up" << endl; - running_ = true ; - timer.setTimeout(s_millisecs_); - timer.start(); -} - - -void LoaderQueue::stopLoader() -{ - timer.stop(); - running_ = false ; - LYXERR(Debug::GRAPHICS) << "LoaderQueue: I'm going to sleep" << endl; -} - - -bool LoaderQueue::running() const -{ - return running_ ; -} - - -void LoaderQueue::touch(Cache::ItemPtr const & item) -{ - if (! cache_set_.insert(item).second) { - list::iterator - it = cache_queue_.begin(); - list::iterator - end = cache_queue_.end(); - - it = std::find(it, end, item); - if (it != end) - cache_queue_.erase(it); - } - cache_queue_.push_front(item); - if (!running_) - startLoader(); -} - - -} // namespace graphics -} // namespace lyx diff --git a/src/graphics/LoaderQueue.cpp b/src/graphics/LoaderQueue.cpp new file mode 100644 index 0000000000..6038dbe4b9 --- /dev/null +++ b/src/graphics/LoaderQueue.cpp @@ -0,0 +1,118 @@ +/** + * \file LoaderQueue.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Alfredo Braunstein + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "LoaderQueue.h" +#include "GraphicsCacheItem.h" + +#include "debug.h" + +#include + +using std::endl; +using std::list; + +namespace lyx { +namespace graphics { + +int LoaderQueue::s_numimages_ = 5; +int LoaderQueue::s_millisecs_ = 500; + + +LoaderQueue & LoaderQueue::get() +{ + static LoaderQueue singleton; + return singleton; +} + + +void LoaderQueue::loadNext() +{ + LYXERR(Debug::GRAPHICS) << "LoaderQueue: " + << cache_queue_.size() + << " items in the queue" << endl; + int counter = s_numimages_; + while (cache_queue_.size() && counter--) { + Cache::ItemPtr ptr = cache_queue_.front(); + cache_set_.erase(ptr); + cache_queue_.pop_front(); + if (ptr->status() == WaitingToLoad) + ptr->startLoading(); + } + if (cache_queue_.size()) { + startLoader(); + } else { + stopLoader(); + } +} + + +void LoaderQueue::setPriority(int numimages , int millisecs) +{ + s_numimages_ = numimages; + s_millisecs_ = millisecs; + LYXERR(Debug::GRAPHICS) << "LoaderQueue: priority set to " + << s_numimages_ << " images at a time, " + << s_millisecs_ << " milliseconds between calls" + << endl; +} + + +LoaderQueue::LoaderQueue() : timer(s_millisecs_, Timeout::ONETIME), + running_(false) +{ + timer.timeout.connect(boost::bind(&LoaderQueue::loadNext, this)); +} + + +void LoaderQueue::startLoader() +{ + LYXERR(Debug::GRAPHICS) << "LoaderQueue: waking up" << endl; + running_ = true ; + timer.setTimeout(s_millisecs_); + timer.start(); +} + + +void LoaderQueue::stopLoader() +{ + timer.stop(); + running_ = false ; + LYXERR(Debug::GRAPHICS) << "LoaderQueue: I'm going to sleep" << endl; +} + + +bool LoaderQueue::running() const +{ + return running_ ; +} + + +void LoaderQueue::touch(Cache::ItemPtr const & item) +{ + if (! cache_set_.insert(item).second) { + list::iterator + it = cache_queue_.begin(); + list::iterator + end = cache_queue_.end(); + + it = std::find(it, end, item); + if (it != end) + cache_queue_.erase(it); + } + cache_queue_.push_front(item); + if (!running_) + startLoader(); +} + + +} // namespace graphics +} // namespace lyx diff --git a/src/graphics/PreviewImage.C b/src/graphics/PreviewImage.C deleted file mode 100644 index 89289e282e..0000000000 --- a/src/graphics/PreviewImage.C +++ /dev/null @@ -1,162 +0,0 @@ -/** - * \file PreviewImage.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Angus Leeming - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "PreviewImage.h" -#include "GraphicsImage.h" -#include "GraphicsLoader.h" -#include "PreviewLoader.h" - -#include "support/filename.h" -#include "support/lyxlib.h" - -#include - -using std::string; - - -namespace lyx { - -using support::FileName; - -namespace graphics { - -class PreviewImage::Impl : public boost::signals::trackable { -public: - /// - Impl(PreviewImage & p, PreviewLoader & l, - string const & s, FileName const & f, double af); - /// - ~Impl(); - /// - Image const * image(); - /// - void statusChanged(); - - /// - PreviewImage const & parent_; - /// - PreviewLoader & ploader_; - /// - Loader iloader_; - /// - string const snippet_; - /// - double const ascent_frac_; -}; - - -PreviewImage::PreviewImage(PreviewLoader & l, - string const & s, - FileName const & f, - double af) - : pimpl_(new Impl(*this, l, s, f, af)) -{} - - -PreviewImage::~PreviewImage() -{} - - -string const & PreviewImage::snippet() const -{ - return pimpl_->snippet_; -} - - -int PreviewImage::ascent() const -{ - Image const * const image = pimpl_->iloader_.image(); - if (!image) - return 0; - - return int(pimpl_->ascent_frac_ * double(image->getHeight())); -} - - -int PreviewImage::descent() const -{ - Image const * const image = pimpl_->iloader_.image(); - if (!image) - return 0; - - // Avoids rounding errors. - return image->getHeight() - ascent(); -} - - -int PreviewImage::width() const -{ - Image const * const image = pimpl_->iloader_.image(); - return image ? image->getWidth() : 0; -} - - -Image const * PreviewImage::image() const -{ - return pimpl_->image(); -} - - -PreviewImage::Impl::Impl(PreviewImage & p, PreviewLoader & l, - string const & s, - FileName const & bf, - double af) - : parent_(p), ploader_(l), iloader_(bf), - snippet_(s), ascent_frac_(af) -{ - iloader_.connect(boost::bind(&Impl::statusChanged, this)); -} - - -PreviewImage::Impl::~Impl() -{ - support::unlink(iloader_.filename()); -} - - -Image const * PreviewImage::Impl::image() -{ - if (iloader_.status() == WaitingToLoad) - iloader_.startLoading(); - - return iloader_.image(); -} - - -void PreviewImage::Impl::statusChanged() -{ - switch (iloader_.status()) { - case WaitingToLoad: - case Loading: - case Converting: - case Loaded: - case ScalingEtc: - break; - - case ErrorNoFile: - case ErrorConverting: - case ErrorLoading: - case ErrorGeneratingPixmap: - case ErrorUnknown: - //lyx::unlink(iloader_.filename()); - ploader_.remove(snippet_); - break; - - case Ready: - support::unlink(iloader_.filename()); - break; - } - ploader_.emitSignal(parent_); -} - -} // namespace graphics -} // namespace lyx diff --git a/src/graphics/PreviewImage.cpp b/src/graphics/PreviewImage.cpp new file mode 100644 index 0000000000..89289e282e --- /dev/null +++ b/src/graphics/PreviewImage.cpp @@ -0,0 +1,162 @@ +/** + * \file PreviewImage.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Angus Leeming + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "PreviewImage.h" +#include "GraphicsImage.h" +#include "GraphicsLoader.h" +#include "PreviewLoader.h" + +#include "support/filename.h" +#include "support/lyxlib.h" + +#include + +using std::string; + + +namespace lyx { + +using support::FileName; + +namespace graphics { + +class PreviewImage::Impl : public boost::signals::trackable { +public: + /// + Impl(PreviewImage & p, PreviewLoader & l, + string const & s, FileName const & f, double af); + /// + ~Impl(); + /// + Image const * image(); + /// + void statusChanged(); + + /// + PreviewImage const & parent_; + /// + PreviewLoader & ploader_; + /// + Loader iloader_; + /// + string const snippet_; + /// + double const ascent_frac_; +}; + + +PreviewImage::PreviewImage(PreviewLoader & l, + string const & s, + FileName const & f, + double af) + : pimpl_(new Impl(*this, l, s, f, af)) +{} + + +PreviewImage::~PreviewImage() +{} + + +string const & PreviewImage::snippet() const +{ + return pimpl_->snippet_; +} + + +int PreviewImage::ascent() const +{ + Image const * const image = pimpl_->iloader_.image(); + if (!image) + return 0; + + return int(pimpl_->ascent_frac_ * double(image->getHeight())); +} + + +int PreviewImage::descent() const +{ + Image const * const image = pimpl_->iloader_.image(); + if (!image) + return 0; + + // Avoids rounding errors. + return image->getHeight() - ascent(); +} + + +int PreviewImage::width() const +{ + Image const * const image = pimpl_->iloader_.image(); + return image ? image->getWidth() : 0; +} + + +Image const * PreviewImage::image() const +{ + return pimpl_->image(); +} + + +PreviewImage::Impl::Impl(PreviewImage & p, PreviewLoader & l, + string const & s, + FileName const & bf, + double af) + : parent_(p), ploader_(l), iloader_(bf), + snippet_(s), ascent_frac_(af) +{ + iloader_.connect(boost::bind(&Impl::statusChanged, this)); +} + + +PreviewImage::Impl::~Impl() +{ + support::unlink(iloader_.filename()); +} + + +Image const * PreviewImage::Impl::image() +{ + if (iloader_.status() == WaitingToLoad) + iloader_.startLoading(); + + return iloader_.image(); +} + + +void PreviewImage::Impl::statusChanged() +{ + switch (iloader_.status()) { + case WaitingToLoad: + case Loading: + case Converting: + case Loaded: + case ScalingEtc: + break; + + case ErrorNoFile: + case ErrorConverting: + case ErrorLoading: + case ErrorGeneratingPixmap: + case ErrorUnknown: + //lyx::unlink(iloader_.filename()); + ploader_.remove(snippet_); + break; + + case Ready: + support::unlink(iloader_.filename()); + break; + } + ploader_.emitSignal(parent_); +} + +} // namespace graphics +} // namespace lyx diff --git a/src/graphics/PreviewLoader.C b/src/graphics/PreviewLoader.C deleted file mode 100644 index 4c32c76928..0000000000 --- a/src/graphics/PreviewLoader.C +++ /dev/null @@ -1,745 +0,0 @@ -/** - * \file PreviewLoader.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Angus Leeming - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "PreviewLoader.h" -#include "PreviewImage.h" -#include "GraphicsCache.h" - -#include "buffer.h" -#include "converter.h" -#include "debug.h" -#include "format.h" -#include "insetiterator.h" -#include "LColor.h" -#include "lyxrc.h" -#include "outputparams.h" -#include "paragraph.h" - -#include "frontends/Application.h" // hexName - -#include "insets/Inset.h" - -#include "support/filetools.h" -#include "support/forkedcall.h" -#include "support/forkedcontr.h" -#include "support/lstrings.h" -#include "support/lyxlib.h" -#include "support/convert.h" - -#include - -#include -#include -#include - -using lyx::support::FileName; - -using std::endl; -using std::find; -using std::fill; -using std::find_if; -using std::make_pair; - -using boost::bind; - -using std::ifstream; -using std::list; -using std::map; -using std::ostringstream; -using std::pair; -using std::vector; -using std::string; - - -namespace { - -typedef pair SnippetPair; - -// A list of all snippets to be converted to previews -typedef list PendingSnippets; - -// Each item in the vector is a pair. -typedef vector BitmapFile; - - -string const unique_filename(string const & bufferpath) -{ - static int theCounter = 0; - string const filename = lyx::convert(theCounter++) + "lyxpreview"; - return lyx::support::addName(bufferpath, filename); -} - - -lyx::Converter const * setConverter() -{ - string const from = "lyxpreview"; - - typedef vector FmtList; - typedef lyx::graphics::Cache GCache; - FmtList const loadableFormats = GCache::get().loadableFormats(); - FmtList::const_iterator it = loadableFormats.begin(); - FmtList::const_iterator const end = loadableFormats.end(); - - for (; it != end; ++it) { - string const to = *it; - if (from == to) - continue; - - lyx::Converter const * ptr = lyx::theConverters().getConverter(from, to); - if (ptr) - return ptr; - } - - static bool first = true; - if (first) { - first = false; - lyx::lyxerr << "PreviewLoader::startLoading()\n" - << "No converter from \"lyxpreview\" format has been " - "defined." - << endl; - } - return 0; -} - - -void setAscentFractions(vector & ascent_fractions, - FileName const & metrics_file) -{ - // If all else fails, then the images will have equal ascents and - // descents. - vector::iterator it = ascent_fractions.begin(); - vector::iterator end = ascent_fractions.end(); - fill(it, end, 0.5); - - ifstream in(metrics_file.toFilesystemEncoding().c_str()); - if (!in.good()) { - lyx::lyxerr[lyx::Debug::GRAPHICS] - << "setAscentFractions(" << metrics_file << ")\n" - << "Unable to open file!" << endl; - return; - } - - bool error = false; - - int snippet_counter = 1; - while (!in.eof() && it != end) { - string snippet; - int id; - double ascent_fraction; - - in >> snippet >> id >> ascent_fraction; - - if (!in.good()) - // eof after all - break; - - error = snippet != "Snippet"; - if (error) - break; - - error = id != snippet_counter; - if (error) - break; - - *it = ascent_fraction; - - ++snippet_counter; - ++it; - } - - if (error) { - lyx::lyxerr[lyx::Debug::GRAPHICS] - << "setAscentFractions(" << metrics_file << ")\n" - << "Error reading file!\n" << endl; - } -} - - -class FindFirst : public std::unary_function { -public: - FindFirst(string const & comp) : comp_(comp) {} - bool operator()(SnippetPair const & sp) const - { - return sp.first == comp_; - } -private: - string const comp_; -}; - - -/// Store info on a currently executing, forked process. -class InProgress { -public: - /// - InProgress() : pid(0) {} - /// - InProgress(string const & filename_base, - PendingSnippets const & pending, - string const & to_format); - /// Remove any files left lying around and kill the forked process. - void stop() const; - - /// - pid_t pid; - /// - string command; - /// - FileName metrics_file; - /// - BitmapFile snippets; -}; - -typedef map InProgressProcesses; - -typedef InProgressProcesses::value_type InProgressProcess; - -} // namespace anon - - - -namespace lyx { - -namespace graphics { - -class PreviewLoader::Impl : public boost::signals::trackable { -public: - /// - Impl(PreviewLoader & p, Buffer const & b); - /// Stop any InProgress items still executing. - ~Impl(); - /// - PreviewImage const * preview(string const & latex_snippet) const; - /// - PreviewLoader::Status status(string const & latex_snippet) const; - /// - void add(string const & latex_snippet); - /// - void remove(string const & latex_snippet); - /// - void startLoading(); - - /// Emit this signal when an image is ready for display. - boost::signal imageReady; - - Buffer const & buffer() const { return buffer_; } - -private: - /// Called by the Forkedcall process that generated the bitmap files. - void finishedGenerating(pid_t, int); - /// - void dumpPreamble(odocstream &) const; - /// - void dumpData(odocstream &, BitmapFile const &) const; - - /** cache_ allows easy retrieval of already-generated images - * using the LaTeX snippet as the identifier. - */ - typedef boost::shared_ptr PreviewImagePtr; - /// - typedef map Cache; - /// - Cache cache_; - - /** pending_ stores the LaTeX snippets in anticipation of them being - * sent to the converter. - */ - PendingSnippets pending_; - - /** in_progress_ stores all forked processes so that we can proceed - * thereafter. - The map uses the conversion commands as its identifiers. - */ - InProgressProcesses in_progress_; - - /// - PreviewLoader & parent_; - /// - Buffer const & buffer_; - /// - double font_scaling_factor_; - - /// We don't own this - static lyx::Converter const * pconverter_; -}; - - -lyx::Converter const * PreviewLoader::Impl::pconverter_; - - -// -// The public interface, defined in PreviewLoader.h -// - -PreviewLoader::PreviewLoader(Buffer const & b) - : pimpl_(new Impl(*this, b)) -{} - - -PreviewLoader::~PreviewLoader() -{} - - -PreviewImage const * PreviewLoader::preview(string const & latex_snippet) const -{ - return pimpl_->preview(latex_snippet); -} - - -PreviewLoader::Status PreviewLoader::status(string const & latex_snippet) const -{ - return pimpl_->status(latex_snippet); -} - - -void PreviewLoader::add(string const & latex_snippet) const -{ - pimpl_->add(latex_snippet); -} - - -void PreviewLoader::remove(string const & latex_snippet) const -{ - pimpl_->remove(latex_snippet); -} - - -void PreviewLoader::startLoading() const -{ - pimpl_->startLoading(); -} - - -boost::signals::connection PreviewLoader::connect(slot_type const & slot) const -{ - return pimpl_->imageReady.connect(slot); -} - - -void PreviewLoader::emitSignal(PreviewImage const & pimage) const -{ - pimpl_->imageReady(pimage); -} - - -Buffer const & PreviewLoader::buffer() const -{ - return pimpl_->buffer(); -} - -} // namespace graphics -} // namespace lyx - - -// The details of the Impl -// ======================= - -namespace { - -class IncrementedFileName { -public: - IncrementedFileName(string const & to_format, - string const & filename_base) - : to_format_(to_format), base_(filename_base), counter_(1) - {} - - SnippetPair const operator()(string const & snippet) - { - ostringstream os; - os << base_ << counter_++ << '.' << to_format_; - string const file = os.str(); - - return make_pair(snippet, FileName(file)); - } - -private: - string const & to_format_; - string const & base_; - int counter_; -}; - - -InProgress::InProgress(string const & filename_base, - PendingSnippets const & pending, - string const & to_format) - : pid(0), - metrics_file(FileName(filename_base + ".metrics")), - snippets(pending.size()) -{ - PendingSnippets::const_iterator pit = pending.begin(); - PendingSnippets::const_iterator pend = pending.end(); - BitmapFile::iterator sit = snippets.begin(); - - std::transform(pit, pend, sit, - IncrementedFileName(to_format, filename_base)); -} - - -void InProgress::stop() const -{ - if (pid) - lyx::support::ForkedcallsController::get().kill(pid, 0); - - if (!metrics_file.empty()) - lyx::support::unlink(metrics_file); - - BitmapFile::const_iterator vit = snippets.begin(); - BitmapFile::const_iterator vend = snippets.end(); - for (; vit != vend; ++vit) { - if (!vit->second.empty()) - lyx::support::unlink(vit->second); - } -} - -} // namespace anon - - -namespace lyx { -namespace graphics { - -PreviewLoader::Impl::Impl(PreviewLoader & p, Buffer const & b) - : parent_(p), buffer_(b), font_scaling_factor_(0.0) -{ - font_scaling_factor_ = 0.01 * lyxrc.dpi * lyxrc.zoom * - convert(lyxrc.preview_scale_factor); - - LYXERR(Debug::GRAPHICS) << "The font scaling factor is " - << font_scaling_factor_ << endl; - - if (!pconverter_) - pconverter_ = setConverter(); -} - - -PreviewLoader::Impl::~Impl() -{ - InProgressProcesses::iterator ipit = in_progress_.begin(); - InProgressProcesses::iterator ipend = in_progress_.end(); - - for (; ipit != ipend; ++ipit) { - ipit->second.stop(); - } -} - - -PreviewImage const * -PreviewLoader::Impl::preview(string const & latex_snippet) const -{ - Cache::const_iterator it = cache_.find(latex_snippet); - return (it == cache_.end()) ? 0 : it->second.get(); -} - - -namespace { - -class FindSnippet : public std::unary_function { -public: - FindSnippet(string const & s) : snippet_(s) {} - bool operator()(InProgressProcess const & process) const - { - BitmapFile const & snippets = process.second.snippets; - BitmapFile::const_iterator beg = snippets.begin(); - BitmapFile::const_iterator end = snippets.end(); - return find_if(beg, end, FindFirst(snippet_)) != end; - } - -private: - string const snippet_; -}; - -} // namespace anon - -PreviewLoader::Status -PreviewLoader::Impl::status(string const & latex_snippet) const -{ - Cache::const_iterator cit = cache_.find(latex_snippet); - if (cit != cache_.end()) - return Ready; - - PendingSnippets::const_iterator pit = pending_.begin(); - PendingSnippets::const_iterator pend = pending_.end(); - - pit = find(pit, pend, latex_snippet); - if (pit != pend) - return InQueue; - - InProgressProcesses::const_iterator ipit = in_progress_.begin(); - InProgressProcesses::const_iterator ipend = in_progress_.end(); - - ipit = find_if(ipit, ipend, FindSnippet(latex_snippet)); - if (ipit != ipend) - return Processing; - - return NotFound; -} - - -void PreviewLoader::Impl::add(string const & latex_snippet) -{ - if (!pconverter_ || status(latex_snippet) != NotFound) - return; - - string const snippet = support::trim(latex_snippet); - if (snippet.empty()) - return; - - LYXERR(Debug::GRAPHICS) << "adding snippet:\n" << snippet << endl; - - pending_.push_back(snippet); -} - - -namespace { - -class EraseSnippet { -public: - EraseSnippet(string const & s) : snippet_(s) {} - void operator()(InProgressProcess & process) - { - BitmapFile & snippets = process.second.snippets; - BitmapFile::iterator it = snippets.begin(); - BitmapFile::iterator end = snippets.end(); - - it = find_if(it, end, FindFirst(snippet_)); - if (it != end) - snippets.erase(it, it+1); - } - -private: - string const & snippet_; -}; - -} // namespace anon - - -void PreviewLoader::Impl::remove(string const & latex_snippet) -{ - Cache::iterator cit = cache_.find(latex_snippet); - if (cit != cache_.end()) - cache_.erase(cit); - - PendingSnippets::iterator pit = pending_.begin(); - PendingSnippets::iterator pend = pending_.end(); - - pending_.erase(std::remove(pit, pend, latex_snippet), pend); - - InProgressProcesses::iterator ipit = in_progress_.begin(); - InProgressProcesses::iterator ipend = in_progress_.end(); - - std::for_each(ipit, ipend, EraseSnippet(latex_snippet)); - - while (ipit != ipend) { - InProgressProcesses::iterator curr = ipit++; - if (curr->second.snippets.empty()) - in_progress_.erase(curr); - } -} - - -void PreviewLoader::Impl::startLoading() -{ - if (pending_.empty() || !pconverter_) - return; - - // Only start the process off after the buffer is loaded from file. - if (!buffer_.fully_loaded()) - return; - - LYXERR(Debug::GRAPHICS) << "PreviewLoader::startLoading()" << endl; - - // As used by the LaTeX file and by the resulting image files - string const directory = buffer_.temppath(); - - string const filename_base = unique_filename(directory); - - // Create an InProgress instance to place in the map of all - // such processes if it starts correctly. - InProgress inprogress(filename_base, pending_, pconverter_->to); - - // clear pending_, so we're ready to start afresh. - pending_.clear(); - - // Output the LaTeX file. - FileName const latexfile(filename_base + ".tex"); - - // FIXME UNICODE - // This creates an utf8 encoded file, but the proper inputenc - // command is missing. - odocfstream of(latexfile.toFilesystemEncoding().c_str()); - if (!of) { - LYXERR(Debug::GRAPHICS) << "PreviewLoader::startLoading()\n" - << "Unable to create LaTeX file\n" - << latexfile << endl; - return; - } - of << "\\batchmode\n"; - dumpPreamble(of); - of << "\n\\begin{document}\n"; - dumpData(of, inprogress.snippets); - of << "\n\\end{document}\n"; - of.close(); - - // The conversion command. - ostringstream cs; - cs << pconverter_->command << ' ' << pconverter_->to << ' ' - << support::quoteName(latexfile.toFilesystemEncoding()) << ' ' - << int(font_scaling_factor_) << ' ' - << theApp()->hexName(LColor::preview) << ' ' - << theApp()->hexName(LColor::background); - - string const command = support::libScriptSearch(cs.str()); - - // Initiate the conversion from LaTeX to bitmap images files. - support::Forkedcall::SignalTypePtr - convert_ptr(new support::Forkedcall::SignalType); - convert_ptr->connect(bind(&Impl::finishedGenerating, this, _1, _2)); - - support::Forkedcall call; - int ret = call.startscript(command, convert_ptr); - - if (ret != 0) { - LYXERR(Debug::GRAPHICS) << "PreviewLoader::startLoading()\n" - << "Unable to start process\n" - << command << endl; - return; - } - - // Store the generation process in a list of all such processes - inprogress.pid = call.pid(); - inprogress.command = command; - in_progress_[inprogress.pid] = inprogress; -} - - -void PreviewLoader::Impl::finishedGenerating(pid_t pid, int retval) -{ - // Paranoia check! - InProgressProcesses::iterator git = in_progress_.find(pid); - if (git == in_progress_.end()) { - lyxerr << "PreviewLoader::finishedGenerating(): unable to find " - "data for PID " << pid << endl; - return; - } - - string const command = git->second.command; - string const status = retval > 0 ? "failed" : "succeeded"; - LYXERR(Debug::GRAPHICS) << "PreviewLoader::finishedInProgress(" - << retval << "): processing " << status - << " for " << command << endl; - if (retval > 0) - return; - - // Read the metrics file, if it exists - vector ascent_fractions(git->second.snippets.size()); - setAscentFractions(ascent_fractions, git->second.metrics_file); - - // Add these newly generated bitmap files to the cache and - // start loading them into LyX. - BitmapFile::const_iterator it = git->second.snippets.begin(); - BitmapFile::const_iterator end = git->second.snippets.end(); - - std::list newimages; - - int metrics_counter = 0; - for (; it != end; ++it, ++metrics_counter) { - string const & snip = it->first; - FileName const & file = it->second; - double af = ascent_fractions[metrics_counter]; - - PreviewImagePtr ptr(new PreviewImage(parent_, snip, file, af)); - cache_[snip] = ptr; - - newimages.push_back(ptr); - } - - // Remove the item from the list of still-executing processes. - in_progress_.erase(git); - - // Tell the outside world - std::list::const_reverse_iterator - nit = newimages.rbegin(); - std::list::const_reverse_iterator - nend = newimages.rend(); - for (; nit != nend; ++nit) { - imageReady(*nit->get()); - } -} - - -void PreviewLoader::Impl::dumpPreamble(odocstream & os) const -{ - // Why on earth is Buffer::makeLaTeXFile a non-const method? - Buffer & tmp = const_cast(buffer_); - // Dump the preamble only. - // We don't need an encoding for runparams since it is not used by - // the preamble. - OutputParams runparams(0); - runparams.flavor = OutputParams::LATEX; - runparams.nice = true; - runparams.moving_arg = true; - runparams.free_spacing = true; - tmp.writeLaTeXSource(os, buffer_.filePath(), runparams, true, false); - - // FIXME! This is a HACK! The proper fix is to control the 'true' - // passed to WriteStream below: - // int InsetMathNest::latex(Buffer const &, odocstream & os, - // OutputParams const & runparams) const - // { - // WriteStream wi(os, runparams.moving_arg, true); - // par_->write(wi); - // return wi.line(); - // } - os << "\n" - << "\\def\\lyxlock{}\n" - << "\n"; - - // Loop over the insets in the buffer and dump all the math-macros. - InsetBase & inset = buffer_.inset(); - InsetIterator it = inset_iterator_begin(inset); - InsetIterator const end = inset_iterator_end(inset); - - for (; it != end; ++it) - if (it->lyxCode() == InsetBase::MATHMACRO_CODE) - it->latex(buffer_, os, runparams); - - // All equation labels appear as "(#)" + preview.sty's rendering of - // the label name - if (lyxrc.preview_hashed_labels) - os << "\\renewcommand{\\theequation}{\\#}\n"; - - // Use the preview style file to ensure that each snippet appears on a - // fresh page. - os << "\n" - << "\\usepackage[active,delayed,dvips,showlabels,lyx]{preview}\n" - << "\n"; -} - - -void PreviewLoader::Impl::dumpData(odocstream & os, - BitmapFile const & vec) const -{ - if (vec.empty()) - return; - - BitmapFile::const_iterator it = vec.begin(); - BitmapFile::const_iterator end = vec.end(); - - for (; it != end; ++it) { - // FIXME UNICODE - os << "\\begin{preview}\n" - << from_utf8(it->first) - << "\n\\end{preview}\n\n"; - } -} - -} // namespace graphics -} // namespace lyx - diff --git a/src/graphics/PreviewLoader.cpp b/src/graphics/PreviewLoader.cpp new file mode 100644 index 0000000000..4c32c76928 --- /dev/null +++ b/src/graphics/PreviewLoader.cpp @@ -0,0 +1,745 @@ +/** + * \file PreviewLoader.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Angus Leeming + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "PreviewLoader.h" +#include "PreviewImage.h" +#include "GraphicsCache.h" + +#include "buffer.h" +#include "converter.h" +#include "debug.h" +#include "format.h" +#include "insetiterator.h" +#include "LColor.h" +#include "lyxrc.h" +#include "outputparams.h" +#include "paragraph.h" + +#include "frontends/Application.h" // hexName + +#include "insets/Inset.h" + +#include "support/filetools.h" +#include "support/forkedcall.h" +#include "support/forkedcontr.h" +#include "support/lstrings.h" +#include "support/lyxlib.h" +#include "support/convert.h" + +#include + +#include +#include +#include + +using lyx::support::FileName; + +using std::endl; +using std::find; +using std::fill; +using std::find_if; +using std::make_pair; + +using boost::bind; + +using std::ifstream; +using std::list; +using std::map; +using std::ostringstream; +using std::pair; +using std::vector; +using std::string; + + +namespace { + +typedef pair SnippetPair; + +// A list of all snippets to be converted to previews +typedef list PendingSnippets; + +// Each item in the vector is a pair. +typedef vector BitmapFile; + + +string const unique_filename(string const & bufferpath) +{ + static int theCounter = 0; + string const filename = lyx::convert(theCounter++) + "lyxpreview"; + return lyx::support::addName(bufferpath, filename); +} + + +lyx::Converter const * setConverter() +{ + string const from = "lyxpreview"; + + typedef vector FmtList; + typedef lyx::graphics::Cache GCache; + FmtList const loadableFormats = GCache::get().loadableFormats(); + FmtList::const_iterator it = loadableFormats.begin(); + FmtList::const_iterator const end = loadableFormats.end(); + + for (; it != end; ++it) { + string const to = *it; + if (from == to) + continue; + + lyx::Converter const * ptr = lyx::theConverters().getConverter(from, to); + if (ptr) + return ptr; + } + + static bool first = true; + if (first) { + first = false; + lyx::lyxerr << "PreviewLoader::startLoading()\n" + << "No converter from \"lyxpreview\" format has been " + "defined." + << endl; + } + return 0; +} + + +void setAscentFractions(vector & ascent_fractions, + FileName const & metrics_file) +{ + // If all else fails, then the images will have equal ascents and + // descents. + vector::iterator it = ascent_fractions.begin(); + vector::iterator end = ascent_fractions.end(); + fill(it, end, 0.5); + + ifstream in(metrics_file.toFilesystemEncoding().c_str()); + if (!in.good()) { + lyx::lyxerr[lyx::Debug::GRAPHICS] + << "setAscentFractions(" << metrics_file << ")\n" + << "Unable to open file!" << endl; + return; + } + + bool error = false; + + int snippet_counter = 1; + while (!in.eof() && it != end) { + string snippet; + int id; + double ascent_fraction; + + in >> snippet >> id >> ascent_fraction; + + if (!in.good()) + // eof after all + break; + + error = snippet != "Snippet"; + if (error) + break; + + error = id != snippet_counter; + if (error) + break; + + *it = ascent_fraction; + + ++snippet_counter; + ++it; + } + + if (error) { + lyx::lyxerr[lyx::Debug::GRAPHICS] + << "setAscentFractions(" << metrics_file << ")\n" + << "Error reading file!\n" << endl; + } +} + + +class FindFirst : public std::unary_function { +public: + FindFirst(string const & comp) : comp_(comp) {} + bool operator()(SnippetPair const & sp) const + { + return sp.first == comp_; + } +private: + string const comp_; +}; + + +/// Store info on a currently executing, forked process. +class InProgress { +public: + /// + InProgress() : pid(0) {} + /// + InProgress(string const & filename_base, + PendingSnippets const & pending, + string const & to_format); + /// Remove any files left lying around and kill the forked process. + void stop() const; + + /// + pid_t pid; + /// + string command; + /// + FileName metrics_file; + /// + BitmapFile snippets; +}; + +typedef map InProgressProcesses; + +typedef InProgressProcesses::value_type InProgressProcess; + +} // namespace anon + + + +namespace lyx { + +namespace graphics { + +class PreviewLoader::Impl : public boost::signals::trackable { +public: + /// + Impl(PreviewLoader & p, Buffer const & b); + /// Stop any InProgress items still executing. + ~Impl(); + /// + PreviewImage const * preview(string const & latex_snippet) const; + /// + PreviewLoader::Status status(string const & latex_snippet) const; + /// + void add(string const & latex_snippet); + /// + void remove(string const & latex_snippet); + /// + void startLoading(); + + /// Emit this signal when an image is ready for display. + boost::signal imageReady; + + Buffer const & buffer() const { return buffer_; } + +private: + /// Called by the Forkedcall process that generated the bitmap files. + void finishedGenerating(pid_t, int); + /// + void dumpPreamble(odocstream &) const; + /// + void dumpData(odocstream &, BitmapFile const &) const; + + /** cache_ allows easy retrieval of already-generated images + * using the LaTeX snippet as the identifier. + */ + typedef boost::shared_ptr PreviewImagePtr; + /// + typedef map Cache; + /// + Cache cache_; + + /** pending_ stores the LaTeX snippets in anticipation of them being + * sent to the converter. + */ + PendingSnippets pending_; + + /** in_progress_ stores all forked processes so that we can proceed + * thereafter. + The map uses the conversion commands as its identifiers. + */ + InProgressProcesses in_progress_; + + /// + PreviewLoader & parent_; + /// + Buffer const & buffer_; + /// + double font_scaling_factor_; + + /// We don't own this + static lyx::Converter const * pconverter_; +}; + + +lyx::Converter const * PreviewLoader::Impl::pconverter_; + + +// +// The public interface, defined in PreviewLoader.h +// + +PreviewLoader::PreviewLoader(Buffer const & b) + : pimpl_(new Impl(*this, b)) +{} + + +PreviewLoader::~PreviewLoader() +{} + + +PreviewImage const * PreviewLoader::preview(string const & latex_snippet) const +{ + return pimpl_->preview(latex_snippet); +} + + +PreviewLoader::Status PreviewLoader::status(string const & latex_snippet) const +{ + return pimpl_->status(latex_snippet); +} + + +void PreviewLoader::add(string const & latex_snippet) const +{ + pimpl_->add(latex_snippet); +} + + +void PreviewLoader::remove(string const & latex_snippet) const +{ + pimpl_->remove(latex_snippet); +} + + +void PreviewLoader::startLoading() const +{ + pimpl_->startLoading(); +} + + +boost::signals::connection PreviewLoader::connect(slot_type const & slot) const +{ + return pimpl_->imageReady.connect(slot); +} + + +void PreviewLoader::emitSignal(PreviewImage const & pimage) const +{ + pimpl_->imageReady(pimage); +} + + +Buffer const & PreviewLoader::buffer() const +{ + return pimpl_->buffer(); +} + +} // namespace graphics +} // namespace lyx + + +// The details of the Impl +// ======================= + +namespace { + +class IncrementedFileName { +public: + IncrementedFileName(string const & to_format, + string const & filename_base) + : to_format_(to_format), base_(filename_base), counter_(1) + {} + + SnippetPair const operator()(string const & snippet) + { + ostringstream os; + os << base_ << counter_++ << '.' << to_format_; + string const file = os.str(); + + return make_pair(snippet, FileName(file)); + } + +private: + string const & to_format_; + string const & base_; + int counter_; +}; + + +InProgress::InProgress(string const & filename_base, + PendingSnippets const & pending, + string const & to_format) + : pid(0), + metrics_file(FileName(filename_base + ".metrics")), + snippets(pending.size()) +{ + PendingSnippets::const_iterator pit = pending.begin(); + PendingSnippets::const_iterator pend = pending.end(); + BitmapFile::iterator sit = snippets.begin(); + + std::transform(pit, pend, sit, + IncrementedFileName(to_format, filename_base)); +} + + +void InProgress::stop() const +{ + if (pid) + lyx::support::ForkedcallsController::get().kill(pid, 0); + + if (!metrics_file.empty()) + lyx::support::unlink(metrics_file); + + BitmapFile::const_iterator vit = snippets.begin(); + BitmapFile::const_iterator vend = snippets.end(); + for (; vit != vend; ++vit) { + if (!vit->second.empty()) + lyx::support::unlink(vit->second); + } +} + +} // namespace anon + + +namespace lyx { +namespace graphics { + +PreviewLoader::Impl::Impl(PreviewLoader & p, Buffer const & b) + : parent_(p), buffer_(b), font_scaling_factor_(0.0) +{ + font_scaling_factor_ = 0.01 * lyxrc.dpi * lyxrc.zoom * + convert(lyxrc.preview_scale_factor); + + LYXERR(Debug::GRAPHICS) << "The font scaling factor is " + << font_scaling_factor_ << endl; + + if (!pconverter_) + pconverter_ = setConverter(); +} + + +PreviewLoader::Impl::~Impl() +{ + InProgressProcesses::iterator ipit = in_progress_.begin(); + InProgressProcesses::iterator ipend = in_progress_.end(); + + for (; ipit != ipend; ++ipit) { + ipit->second.stop(); + } +} + + +PreviewImage const * +PreviewLoader::Impl::preview(string const & latex_snippet) const +{ + Cache::const_iterator it = cache_.find(latex_snippet); + return (it == cache_.end()) ? 0 : it->second.get(); +} + + +namespace { + +class FindSnippet : public std::unary_function { +public: + FindSnippet(string const & s) : snippet_(s) {} + bool operator()(InProgressProcess const & process) const + { + BitmapFile const & snippets = process.second.snippets; + BitmapFile::const_iterator beg = snippets.begin(); + BitmapFile::const_iterator end = snippets.end(); + return find_if(beg, end, FindFirst(snippet_)) != end; + } + +private: + string const snippet_; +}; + +} // namespace anon + +PreviewLoader::Status +PreviewLoader::Impl::status(string const & latex_snippet) const +{ + Cache::const_iterator cit = cache_.find(latex_snippet); + if (cit != cache_.end()) + return Ready; + + PendingSnippets::const_iterator pit = pending_.begin(); + PendingSnippets::const_iterator pend = pending_.end(); + + pit = find(pit, pend, latex_snippet); + if (pit != pend) + return InQueue; + + InProgressProcesses::const_iterator ipit = in_progress_.begin(); + InProgressProcesses::const_iterator ipend = in_progress_.end(); + + ipit = find_if(ipit, ipend, FindSnippet(latex_snippet)); + if (ipit != ipend) + return Processing; + + return NotFound; +} + + +void PreviewLoader::Impl::add(string const & latex_snippet) +{ + if (!pconverter_ || status(latex_snippet) != NotFound) + return; + + string const snippet = support::trim(latex_snippet); + if (snippet.empty()) + return; + + LYXERR(Debug::GRAPHICS) << "adding snippet:\n" << snippet << endl; + + pending_.push_back(snippet); +} + + +namespace { + +class EraseSnippet { +public: + EraseSnippet(string const & s) : snippet_(s) {} + void operator()(InProgressProcess & process) + { + BitmapFile & snippets = process.second.snippets; + BitmapFile::iterator it = snippets.begin(); + BitmapFile::iterator end = snippets.end(); + + it = find_if(it, end, FindFirst(snippet_)); + if (it != end) + snippets.erase(it, it+1); + } + +private: + string const & snippet_; +}; + +} // namespace anon + + +void PreviewLoader::Impl::remove(string const & latex_snippet) +{ + Cache::iterator cit = cache_.find(latex_snippet); + if (cit != cache_.end()) + cache_.erase(cit); + + PendingSnippets::iterator pit = pending_.begin(); + PendingSnippets::iterator pend = pending_.end(); + + pending_.erase(std::remove(pit, pend, latex_snippet), pend); + + InProgressProcesses::iterator ipit = in_progress_.begin(); + InProgressProcesses::iterator ipend = in_progress_.end(); + + std::for_each(ipit, ipend, EraseSnippet(latex_snippet)); + + while (ipit != ipend) { + InProgressProcesses::iterator curr = ipit++; + if (curr->second.snippets.empty()) + in_progress_.erase(curr); + } +} + + +void PreviewLoader::Impl::startLoading() +{ + if (pending_.empty() || !pconverter_) + return; + + // Only start the process off after the buffer is loaded from file. + if (!buffer_.fully_loaded()) + return; + + LYXERR(Debug::GRAPHICS) << "PreviewLoader::startLoading()" << endl; + + // As used by the LaTeX file and by the resulting image files + string const directory = buffer_.temppath(); + + string const filename_base = unique_filename(directory); + + // Create an InProgress instance to place in the map of all + // such processes if it starts correctly. + InProgress inprogress(filename_base, pending_, pconverter_->to); + + // clear pending_, so we're ready to start afresh. + pending_.clear(); + + // Output the LaTeX file. + FileName const latexfile(filename_base + ".tex"); + + // FIXME UNICODE + // This creates an utf8 encoded file, but the proper inputenc + // command is missing. + odocfstream of(latexfile.toFilesystemEncoding().c_str()); + if (!of) { + LYXERR(Debug::GRAPHICS) << "PreviewLoader::startLoading()\n" + << "Unable to create LaTeX file\n" + << latexfile << endl; + return; + } + of << "\\batchmode\n"; + dumpPreamble(of); + of << "\n\\begin{document}\n"; + dumpData(of, inprogress.snippets); + of << "\n\\end{document}\n"; + of.close(); + + // The conversion command. + ostringstream cs; + cs << pconverter_->command << ' ' << pconverter_->to << ' ' + << support::quoteName(latexfile.toFilesystemEncoding()) << ' ' + << int(font_scaling_factor_) << ' ' + << theApp()->hexName(LColor::preview) << ' ' + << theApp()->hexName(LColor::background); + + string const command = support::libScriptSearch(cs.str()); + + // Initiate the conversion from LaTeX to bitmap images files. + support::Forkedcall::SignalTypePtr + convert_ptr(new support::Forkedcall::SignalType); + convert_ptr->connect(bind(&Impl::finishedGenerating, this, _1, _2)); + + support::Forkedcall call; + int ret = call.startscript(command, convert_ptr); + + if (ret != 0) { + LYXERR(Debug::GRAPHICS) << "PreviewLoader::startLoading()\n" + << "Unable to start process\n" + << command << endl; + return; + } + + // Store the generation process in a list of all such processes + inprogress.pid = call.pid(); + inprogress.command = command; + in_progress_[inprogress.pid] = inprogress; +} + + +void PreviewLoader::Impl::finishedGenerating(pid_t pid, int retval) +{ + // Paranoia check! + InProgressProcesses::iterator git = in_progress_.find(pid); + if (git == in_progress_.end()) { + lyxerr << "PreviewLoader::finishedGenerating(): unable to find " + "data for PID " << pid << endl; + return; + } + + string const command = git->second.command; + string const status = retval > 0 ? "failed" : "succeeded"; + LYXERR(Debug::GRAPHICS) << "PreviewLoader::finishedInProgress(" + << retval << "): processing " << status + << " for " << command << endl; + if (retval > 0) + return; + + // Read the metrics file, if it exists + vector ascent_fractions(git->second.snippets.size()); + setAscentFractions(ascent_fractions, git->second.metrics_file); + + // Add these newly generated bitmap files to the cache and + // start loading them into LyX. + BitmapFile::const_iterator it = git->second.snippets.begin(); + BitmapFile::const_iterator end = git->second.snippets.end(); + + std::list newimages; + + int metrics_counter = 0; + for (; it != end; ++it, ++metrics_counter) { + string const & snip = it->first; + FileName const & file = it->second; + double af = ascent_fractions[metrics_counter]; + + PreviewImagePtr ptr(new PreviewImage(parent_, snip, file, af)); + cache_[snip] = ptr; + + newimages.push_back(ptr); + } + + // Remove the item from the list of still-executing processes. + in_progress_.erase(git); + + // Tell the outside world + std::list::const_reverse_iterator + nit = newimages.rbegin(); + std::list::const_reverse_iterator + nend = newimages.rend(); + for (; nit != nend; ++nit) { + imageReady(*nit->get()); + } +} + + +void PreviewLoader::Impl::dumpPreamble(odocstream & os) const +{ + // Why on earth is Buffer::makeLaTeXFile a non-const method? + Buffer & tmp = const_cast(buffer_); + // Dump the preamble only. + // We don't need an encoding for runparams since it is not used by + // the preamble. + OutputParams runparams(0); + runparams.flavor = OutputParams::LATEX; + runparams.nice = true; + runparams.moving_arg = true; + runparams.free_spacing = true; + tmp.writeLaTeXSource(os, buffer_.filePath(), runparams, true, false); + + // FIXME! This is a HACK! The proper fix is to control the 'true' + // passed to WriteStream below: + // int InsetMathNest::latex(Buffer const &, odocstream & os, + // OutputParams const & runparams) const + // { + // WriteStream wi(os, runparams.moving_arg, true); + // par_->write(wi); + // return wi.line(); + // } + os << "\n" + << "\\def\\lyxlock{}\n" + << "\n"; + + // Loop over the insets in the buffer and dump all the math-macros. + InsetBase & inset = buffer_.inset(); + InsetIterator it = inset_iterator_begin(inset); + InsetIterator const end = inset_iterator_end(inset); + + for (; it != end; ++it) + if (it->lyxCode() == InsetBase::MATHMACRO_CODE) + it->latex(buffer_, os, runparams); + + // All equation labels appear as "(#)" + preview.sty's rendering of + // the label name + if (lyxrc.preview_hashed_labels) + os << "\\renewcommand{\\theequation}{\\#}\n"; + + // Use the preview style file to ensure that each snippet appears on a + // fresh page. + os << "\n" + << "\\usepackage[active,delayed,dvips,showlabels,lyx]{preview}\n" + << "\n"; +} + + +void PreviewLoader::Impl::dumpData(odocstream & os, + BitmapFile const & vec) const +{ + if (vec.empty()) + return; + + BitmapFile::const_iterator it = vec.begin(); + BitmapFile::const_iterator end = vec.end(); + + for (; it != end; ++it) { + // FIXME UNICODE + os << "\\begin{preview}\n" + << from_utf8(it->first) + << "\n\\end{preview}\n\n"; + } +} + +} // namespace graphics +} // namespace lyx + diff --git a/src/graphics/Previews.C b/src/graphics/Previews.C deleted file mode 100644 index 0da83d901c..0000000000 --- a/src/graphics/Previews.C +++ /dev/null @@ -1,99 +0,0 @@ -/** - * \file Previews.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Angus Leeming - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "Previews.h" -#include "PreviewLoader.h" - -#include "buffer.h" -#include "insetiterator.h" -#include "lyxrc.h" -#include "paragraph.h" - -#include "insets/Inset.h" - - -namespace lyx { - -namespace graphics { - -LyXRC_PreviewStatus Previews::status() -{ - return lyxrc.preview; -} - - -Previews & Previews::get() -{ - static Previews singleton; - return singleton; -} - - -class Previews::Impl { -public: - /// - typedef boost::shared_ptr PreviewLoaderPtr; - /// - typedef std::map CacheType; - /// - CacheType cache; -}; - - -Previews::Previews() - : pimpl_(new Impl) -{} - - -Previews::~Previews() -{} - - -PreviewLoader & Previews::loader(Buffer const & buffer) const -{ - Impl::CacheType::iterator it = pimpl_->cache.find(&buffer); - - if (it == pimpl_->cache.end()) { - Impl::PreviewLoaderPtr ptr(new PreviewLoader(buffer)); - pimpl_->cache[&buffer] = ptr; - return *ptr.get(); - } - - return *it->second.get(); -} - - -void Previews::removeLoader(Buffer const & buffer) const -{ - Impl::CacheType::iterator it = pimpl_->cache.find(&buffer); - - if (it != pimpl_->cache.end()) - pimpl_->cache.erase(it); -} - - -void Previews::generateBufferPreviews(Buffer const & buffer) const -{ - PreviewLoader & ploader = loader(buffer); - - InsetBase & inset = buffer.inset(); - InsetIterator it = inset_iterator_begin(inset); - InsetIterator const end = inset_iterator_end(inset); - - for (; it != end; ++it) - it->addPreview(ploader); - - ploader.startLoading(); -} - -} // namespace graphics -} // namespace lyx diff --git a/src/graphics/Previews.cpp b/src/graphics/Previews.cpp new file mode 100644 index 0000000000..0da83d901c --- /dev/null +++ b/src/graphics/Previews.cpp @@ -0,0 +1,99 @@ +/** + * \file Previews.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Angus Leeming + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "Previews.h" +#include "PreviewLoader.h" + +#include "buffer.h" +#include "insetiterator.h" +#include "lyxrc.h" +#include "paragraph.h" + +#include "insets/Inset.h" + + +namespace lyx { + +namespace graphics { + +LyXRC_PreviewStatus Previews::status() +{ + return lyxrc.preview; +} + + +Previews & Previews::get() +{ + static Previews singleton; + return singleton; +} + + +class Previews::Impl { +public: + /// + typedef boost::shared_ptr PreviewLoaderPtr; + /// + typedef std::map CacheType; + /// + CacheType cache; +}; + + +Previews::Previews() + : pimpl_(new Impl) +{} + + +Previews::~Previews() +{} + + +PreviewLoader & Previews::loader(Buffer const & buffer) const +{ + Impl::CacheType::iterator it = pimpl_->cache.find(&buffer); + + if (it == pimpl_->cache.end()) { + Impl::PreviewLoaderPtr ptr(new PreviewLoader(buffer)); + pimpl_->cache[&buffer] = ptr; + return *ptr.get(); + } + + return *it->second.get(); +} + + +void Previews::removeLoader(Buffer const & buffer) const +{ + Impl::CacheType::iterator it = pimpl_->cache.find(&buffer); + + if (it != pimpl_->cache.end()) + pimpl_->cache.erase(it); +} + + +void Previews::generateBufferPreviews(Buffer const & buffer) const +{ + PreviewLoader & ploader = loader(buffer); + + InsetBase & inset = buffer.inset(); + InsetIterator it = inset_iterator_begin(inset); + InsetIterator const end = inset_iterator_end(inset); + + for (; it != end; ++it) + it->addPreview(ploader); + + ploader.startLoading(); +} + +} // namespace graphics +} // namespace lyx diff --git a/src/mathed/InsetFormulaMacro.C b/src/mathed/InsetFormulaMacro.C deleted file mode 100644 index 1a17f8705c..0000000000 --- a/src/mathed/InsetFormulaMacro.C +++ /dev/null @@ -1,188 +0,0 @@ -/** - * \file InsetFormulaMacro.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Alejandro Aguilar Sierra - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetFormulaMacro.h" -#include "MathMacroTable.h" -#include "MathMacroTemplate.h" - -#include "BufferView.h" -#include "cursor.h" -#include "debug.h" -#include "gettext.h" -#include "LColor.h" -#include "lyxlex.h" -#include "outputparams.h" - -#include "frontends/FontMetrics.h" -#include "frontends/Painter.h" - -#include "support/lstrings.h" - -#include - - -namespace lyx { - -using odocstream; -using support::bformat; - -using std::string; -using std::auto_ptr; -using std::ostream; -using std::endl; - - - -InsetFormulaMacro::InsetFormulaMacro() - : InsetMathNest(2), name_("unknownA") -{} - - -InsetFormulaMacro::InsetFormulaMacro - (string const & name, int nargs, string const & type) - : InsetMathNest(2), name_(name) -{ - MathMacroTable::create(MathAtom(new MathMacroTemplate(name, nargs, type))); -} - - -InsetFormulaMacro::InsetFormulaMacro(string const & s) - : InsetMathNest(2), name_("unknownB") -{ - std::istringstream is(s); - read(is); -} - - -auto_ptr InsetFormulaMacro::clone() const -{ - return auto_ptr(new InsetFormulaMacro(*this)); -} - - -void InsetFormulaMacro::write(Buffer const &, ostream & os) const -{ - os << "FormulaMacro\n"; - WriteStream wi(os, false, false); - tmpl()->write(wi); -} - - -int InsetFormulaMacro::latex(Buffer const &, odocstream & os, - OutputParams const & runparams) const -{ - //lyxerr << "InsetFormulaMacro::latex" << endl; - WriteStream wi(os, runparams.moving_arg, true); - tmpl()->write(wi); - return 2; -} - - -int InsetFormulaMacro::plaintext(Buffer const &, odocstream & os, - OutputParams const &) const -{ - odocstringstream oss; - WriteStream wi(oss, false, true); - tmpl()->write(wi); - - docstring const str = oss.str(); - os << str; - return str.size(); -} - - -int InsetFormulaMacro::docbook(Buffer const & buf, ostream & os, - OutputParams const & runparams) const -{ - return plaintext(buf, os, runparams); -} - - -void InsetFormulaMacro::read(Buffer const &, LyXLex & lex) -{ - read(lex.getStream()); -} - - -void InsetFormulaMacro::read(std::istream & is) -{ - auto_ptr p(new MathMacroTemplate(is)); - name_ = p->name(); - MathMacroTable::create(MathAtom(p.release())); -} - - -string InsetFormulaMacro::prefix() const -{ - return to_utf8(bformat(_(" Macro: %1$s: "), lyx::from_utf8(name_))); -} - - -bool InsetFormulaMacro::metrics(MetricsInfo & mi, Dimension & dim) const -{ - //lyxerr << "InsetFormulaMacro: " << this << " -- " << &tmpl() << endl; - tmpl()->metrics(mi, dim); - dim.asc += 5; - dim.des += 5; - dim.wid += 10 + theFontMetrics(mi.base.font).width(prefix()); - bool const changed = dim_ != dim; - dim_ = dim; - return changed; -} - - -void InsetFormulaMacro::draw(PainterInfo & p, int x, int y) const -{ - // label - LyXFont font = p.base.font; - font.setColor(LColor::math); - - PainterInfo pi(p.base.bv, p.pain); - pi.base.style = LM_ST_TEXT; - pi.base.font = font; - - int const a = y - dim_.asc + 1; - int const w = dim_.wid - 2; - int const h = dim_.height() - 2; - - // LColor::mathbg used to be "AntiqueWhite" but is "linen" now, too - pi.pain.fillRectangle(x, a, w, h, LColor::mathmacrobg); - pi.pain.rectangle(x, a, w, h, LColor::mathframe); - -#ifdef WITH_WARNINGS -#warning FIXME -#endif -#if 0 - LCursor & cur = p.base.bv->cursor(); - if (cur.isInside(this)) - cur.drawSelection(pi); -#endif - - pi.pain.text(x + 2, y, prefix(), font); - - // body - tmpl()->draw(pi, - x + theFontMetrics(p.base.font).width(prefix()) + 5, - y); - - setPosCache(pi, x, y); -} - - -MathAtom & InsetFormulaMacro::tmpl() const -{ - return MathMacroTable::provide(name_); -} - - -} // namespace lyx diff --git a/src/mathed/InsetFormulaMacro.cpp b/src/mathed/InsetFormulaMacro.cpp new file mode 100644 index 0000000000..1a17f8705c --- /dev/null +++ b/src/mathed/InsetFormulaMacro.cpp @@ -0,0 +1,188 @@ +/** + * \file InsetFormulaMacro.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Alejandro Aguilar Sierra + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetFormulaMacro.h" +#include "MathMacroTable.h" +#include "MathMacroTemplate.h" + +#include "BufferView.h" +#include "cursor.h" +#include "debug.h" +#include "gettext.h" +#include "LColor.h" +#include "lyxlex.h" +#include "outputparams.h" + +#include "frontends/FontMetrics.h" +#include "frontends/Painter.h" + +#include "support/lstrings.h" + +#include + + +namespace lyx { + +using odocstream; +using support::bformat; + +using std::string; +using std::auto_ptr; +using std::ostream; +using std::endl; + + + +InsetFormulaMacro::InsetFormulaMacro() + : InsetMathNest(2), name_("unknownA") +{} + + +InsetFormulaMacro::InsetFormulaMacro + (string const & name, int nargs, string const & type) + : InsetMathNest(2), name_(name) +{ + MathMacroTable::create(MathAtom(new MathMacroTemplate(name, nargs, type))); +} + + +InsetFormulaMacro::InsetFormulaMacro(string const & s) + : InsetMathNest(2), name_("unknownB") +{ + std::istringstream is(s); + read(is); +} + + +auto_ptr InsetFormulaMacro::clone() const +{ + return auto_ptr(new InsetFormulaMacro(*this)); +} + + +void InsetFormulaMacro::write(Buffer const &, ostream & os) const +{ + os << "FormulaMacro\n"; + WriteStream wi(os, false, false); + tmpl()->write(wi); +} + + +int InsetFormulaMacro::latex(Buffer const &, odocstream & os, + OutputParams const & runparams) const +{ + //lyxerr << "InsetFormulaMacro::latex" << endl; + WriteStream wi(os, runparams.moving_arg, true); + tmpl()->write(wi); + return 2; +} + + +int InsetFormulaMacro::plaintext(Buffer const &, odocstream & os, + OutputParams const &) const +{ + odocstringstream oss; + WriteStream wi(oss, false, true); + tmpl()->write(wi); + + docstring const str = oss.str(); + os << str; + return str.size(); +} + + +int InsetFormulaMacro::docbook(Buffer const & buf, ostream & os, + OutputParams const & runparams) const +{ + return plaintext(buf, os, runparams); +} + + +void InsetFormulaMacro::read(Buffer const &, LyXLex & lex) +{ + read(lex.getStream()); +} + + +void InsetFormulaMacro::read(std::istream & is) +{ + auto_ptr p(new MathMacroTemplate(is)); + name_ = p->name(); + MathMacroTable::create(MathAtom(p.release())); +} + + +string InsetFormulaMacro::prefix() const +{ + return to_utf8(bformat(_(" Macro: %1$s: "), lyx::from_utf8(name_))); +} + + +bool InsetFormulaMacro::metrics(MetricsInfo & mi, Dimension & dim) const +{ + //lyxerr << "InsetFormulaMacro: " << this << " -- " << &tmpl() << endl; + tmpl()->metrics(mi, dim); + dim.asc += 5; + dim.des += 5; + dim.wid += 10 + theFontMetrics(mi.base.font).width(prefix()); + bool const changed = dim_ != dim; + dim_ = dim; + return changed; +} + + +void InsetFormulaMacro::draw(PainterInfo & p, int x, int y) const +{ + // label + LyXFont font = p.base.font; + font.setColor(LColor::math); + + PainterInfo pi(p.base.bv, p.pain); + pi.base.style = LM_ST_TEXT; + pi.base.font = font; + + int const a = y - dim_.asc + 1; + int const w = dim_.wid - 2; + int const h = dim_.height() - 2; + + // LColor::mathbg used to be "AntiqueWhite" but is "linen" now, too + pi.pain.fillRectangle(x, a, w, h, LColor::mathmacrobg); + pi.pain.rectangle(x, a, w, h, LColor::mathframe); + +#ifdef WITH_WARNINGS +#warning FIXME +#endif +#if 0 + LCursor & cur = p.base.bv->cursor(); + if (cur.isInside(this)) + cur.drawSelection(pi); +#endif + + pi.pain.text(x + 2, y, prefix(), font); + + // body + tmpl()->draw(pi, + x + theFontMetrics(p.base.font).width(prefix()) + 5, + y); + + setPosCache(pi, x, y); +} + + +MathAtom & InsetFormulaMacro::tmpl() const +{ + return MathMacroTable::provide(name_); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMath.C b/src/mathed/InsetMath.C deleted file mode 100644 index 64db5a2180..0000000000 --- a/src/mathed/InsetMath.C +++ /dev/null @@ -1,165 +0,0 @@ -/** - * \file InsetMath.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Alejandro Aguilar Sierra - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMath.h" -#include "MathData.h" -#include "MathStream.h" -#include "gettext.h" -#include "debug.h" - -#include "support/lstrings.h" -#include "support/textutils.h" - -#include - -using std::endl; - -namespace lyx { - - - -MathArray & InsetMath::cell(idx_type) -{ - static MathArray dummyCell; - lyxerr << BOOST_CURRENT_FUNCTION << ": I don't have any cell" << endl; - return dummyCell; -} - - -MathArray const & InsetMath::cell(idx_type) const -{ - static MathArray dummyCell; - lyxerr << BOOST_CURRENT_FUNCTION << ": I don't have any cell" << endl; - return dummyCell; -} - - -void InsetMath::dump() const -{ - lyxerr << "---------------------------------------------" << endl; - odocstringstream os; - WriteStream wi(os, false, true); - write(wi); - lyxerr << to_utf8(os.str()); - lyxerr << "\n---------------------------------------------" << endl; -} - - -void InsetMath::metricsT(TextMetricsInfo const &, Dimension &) const -{ -#ifdef WITH_WARNINGS - lyxerr << "InsetMath::metricsT(Text) called directly!" << endl; -#endif -} - - -void InsetMath::drawT(TextPainter &, int, int) const -{ -#ifdef WITH_WARNINGS - lyxerr << "InsetMath::drawT(Text) called directly!" << endl; -#endif -} - - - -void InsetMath::write(WriteStream & os) const -{ - docstring const s = name(); - os << "\\" << s; - // We need an extra ' ' unless this is a single-char-non-ASCII name - // or anything non-ASCII follows - if (s.size() != 1 || isAlphaASCII(s[0])) - os.pendingSpace(true); -} - - -int InsetMath::plaintext(Buffer const &, odocstream &, - OutputParams const &) const -{ - // all math plain text output shall take place in InsetMathHull - BOOST_ASSERT(false); - return 0; -} - - -void InsetMath::normalize(NormalStream & os) const -{ - os << '[' << name() << "] "; -} - - -void InsetMath::octave(OctaveStream & os) const -{ - NormalStream ns(os.os()); - normalize(ns); -} - - -void InsetMath::maple(MapleStream & os) const -{ - NormalStream ns(os.os()); - normalize(ns); -} - - -void InsetMath::maxima(MaximaStream & os) const -{ - MapleStream ns(os.os()); - maple(ns); -} - - -void InsetMath::mathematica(MathematicaStream & os) const -{ - NormalStream ns(os.os()); - normalize(ns); -} - - -void InsetMath::mathmlize(MathStream & os) const -{ - NormalStream ns(os.os()); - normalize(ns); -} - - -HullType InsetMath::getType() const -{ - return hullNone; -} - - -docstring InsetMath::name() const -{ - return from_ascii("unknown"); -} - - -std::ostream & operator<<(std::ostream & os, MathAtom const & at) -{ - odocstringstream oss; - WriteStream wi(oss, false, false); - at->write(wi); - return os << to_utf8(oss.str()); -} - - -odocstream & operator<<(odocstream & os, MathAtom const & at) -{ - WriteStream wi(os, false, false); - at->write(wi); - return os; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMath.cpp b/src/mathed/InsetMath.cpp new file mode 100644 index 0000000000..64db5a2180 --- /dev/null +++ b/src/mathed/InsetMath.cpp @@ -0,0 +1,165 @@ +/** + * \file InsetMath.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Alejandro Aguilar Sierra + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMath.h" +#include "MathData.h" +#include "MathStream.h" +#include "gettext.h" +#include "debug.h" + +#include "support/lstrings.h" +#include "support/textutils.h" + +#include + +using std::endl; + +namespace lyx { + + + +MathArray & InsetMath::cell(idx_type) +{ + static MathArray dummyCell; + lyxerr << BOOST_CURRENT_FUNCTION << ": I don't have any cell" << endl; + return dummyCell; +} + + +MathArray const & InsetMath::cell(idx_type) const +{ + static MathArray dummyCell; + lyxerr << BOOST_CURRENT_FUNCTION << ": I don't have any cell" << endl; + return dummyCell; +} + + +void InsetMath::dump() const +{ + lyxerr << "---------------------------------------------" << endl; + odocstringstream os; + WriteStream wi(os, false, true); + write(wi); + lyxerr << to_utf8(os.str()); + lyxerr << "\n---------------------------------------------" << endl; +} + + +void InsetMath::metricsT(TextMetricsInfo const &, Dimension &) const +{ +#ifdef WITH_WARNINGS + lyxerr << "InsetMath::metricsT(Text) called directly!" << endl; +#endif +} + + +void InsetMath::drawT(TextPainter &, int, int) const +{ +#ifdef WITH_WARNINGS + lyxerr << "InsetMath::drawT(Text) called directly!" << endl; +#endif +} + + + +void InsetMath::write(WriteStream & os) const +{ + docstring const s = name(); + os << "\\" << s; + // We need an extra ' ' unless this is a single-char-non-ASCII name + // or anything non-ASCII follows + if (s.size() != 1 || isAlphaASCII(s[0])) + os.pendingSpace(true); +} + + +int InsetMath::plaintext(Buffer const &, odocstream &, + OutputParams const &) const +{ + // all math plain text output shall take place in InsetMathHull + BOOST_ASSERT(false); + return 0; +} + + +void InsetMath::normalize(NormalStream & os) const +{ + os << '[' << name() << "] "; +} + + +void InsetMath::octave(OctaveStream & os) const +{ + NormalStream ns(os.os()); + normalize(ns); +} + + +void InsetMath::maple(MapleStream & os) const +{ + NormalStream ns(os.os()); + normalize(ns); +} + + +void InsetMath::maxima(MaximaStream & os) const +{ + MapleStream ns(os.os()); + maple(ns); +} + + +void InsetMath::mathematica(MathematicaStream & os) const +{ + NormalStream ns(os.os()); + normalize(ns); +} + + +void InsetMath::mathmlize(MathStream & os) const +{ + NormalStream ns(os.os()); + normalize(ns); +} + + +HullType InsetMath::getType() const +{ + return hullNone; +} + + +docstring InsetMath::name() const +{ + return from_ascii("unknown"); +} + + +std::ostream & operator<<(std::ostream & os, MathAtom const & at) +{ + odocstringstream oss; + WriteStream wi(oss, false, false); + at->write(wi); + return os << to_utf8(oss.str()); +} + + +odocstream & operator<<(odocstream & os, MathAtom const & at) +{ + WriteStream wi(os, false, false); + at->write(wi); + return os; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathAMSArray.C b/src/mathed/InsetMathAMSArray.C deleted file mode 100644 index 3febc45cb1..0000000000 --- a/src/mathed/InsetMathAMSArray.C +++ /dev/null @@ -1,155 +0,0 @@ -/** - * \file InsetMathAMSArray.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "LaTeXFeatures.h" -#include "InsetMathAMSArray.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathStream.h" -#include "MathSupport.h" - -#include "funcrequest.h" -#include "FuncStatus.h" -#include "gettext.h" - -#include "support/lstrings.h" -#include "support/std_ostream.h" - -using std::auto_ptr; - -namespace lyx { - -using support::bformat; - - -InsetMathAMSArray::InsetMathAMSArray(docstring const & name, int m, int n) - : InsetMathGrid(m, n), name_(name) -{} - - -InsetMathAMSArray::InsetMathAMSArray(docstring const & name) - : InsetMathGrid(1, 1), name_(name) -{} - - -auto_ptr InsetMathAMSArray::doClone() const -{ - return auto_ptr(new InsetMathAMSArray(*this)); -} - - -char const * InsetMathAMSArray::name_left() const -{ - if (name_ == "bmatrix") - return "["; - if (name_ == "Bmatrix") - return "{"; - if (name_ == "vmatrix") - return "|"; - if (name_ == "Vmatrix") - return "Vert"; - if (name_ == "pmatrix") - return "("; - return "."; -} - - -char const * InsetMathAMSArray::name_right() const -{ - if (name_ == "bmatrix") - return "]"; - if (name_ == "Bmatrix") - return "}"; - if (name_ == "vmatrix") - return "|"; - if (name_ == "Vmatrix") - return "Vert"; - if (name_ == "pmatrix") - return ")"; - return "."; -} - - -bool InsetMathAMSArray::metrics(MetricsInfo & mi, Dimension & dim) const -{ - ArrayChanger dummy(mi.base); - InsetMathGrid::metrics(mi, dim); - dim.wid += 14; - bool const changed = dim_ != dim; - dim_ = dim; - return changed; -} - - -void InsetMathAMSArray::draw(PainterInfo & pi, int x, int y) const -{ - int const yy = y - dim_.ascent(); - // Drawing the deco after an ArrayChanger does not work - mathed_draw_deco(pi, x + 1, yy, 5, dim_.height(), from_ascii(name_left())); - mathed_draw_deco(pi, x + dim_.width() - 8, yy, 5, dim_.height(), from_ascii(name_right())); - ArrayChanger dummy(pi.base); - InsetMathGrid::drawWithMargin(pi, x, y, 6, 8); -} - - -bool InsetMathAMSArray::getStatus(LCursor & cur, FuncRequest const & cmd, - FuncStatus & flag) const -{ - switch (cmd.action) { - case LFUN_TABULAR_FEATURE: { - docstring const & s = cmd.argument(); - if (s == "add-vline-left" || s == "add-vline-right") { - flag.message(bformat( - from_utf8(N_("Can't add vertical grid lines in '%1$s'")), name_)); - flag.enabled(false); - return true; - } - return InsetMathGrid::getStatus(cur, cmd, flag); - } - default: - return InsetMathGrid::getStatus(cur, cmd, flag); - } -} - - -void InsetMathAMSArray::write(WriteStream & os) const -{ - os << "\\begin{" << name_ << '}'; - InsetMathGrid::write(os); - os << "\\end{" << name_ << '}'; -} - - -void InsetMathAMSArray::infoize(odocstream & os) const -{ - docstring name = name_; - name[0] = support::uppercase(name[0]); - os << name << ' '; -} - - -void InsetMathAMSArray::normalize(NormalStream & os) const -{ - os << '[' << name_ << ' '; - InsetMathGrid::normalize(os); - os << ']'; -} - - -void InsetMathAMSArray::validate(LaTeXFeatures & features) const -{ - features.require("amsmath"); - InsetMathGrid::validate(features); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathAMSArray.cpp b/src/mathed/InsetMathAMSArray.cpp new file mode 100644 index 0000000000..3febc45cb1 --- /dev/null +++ b/src/mathed/InsetMathAMSArray.cpp @@ -0,0 +1,155 @@ +/** + * \file InsetMathAMSArray.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "LaTeXFeatures.h" +#include "InsetMathAMSArray.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathStream.h" +#include "MathSupport.h" + +#include "funcrequest.h" +#include "FuncStatus.h" +#include "gettext.h" + +#include "support/lstrings.h" +#include "support/std_ostream.h" + +using std::auto_ptr; + +namespace lyx { + +using support::bformat; + + +InsetMathAMSArray::InsetMathAMSArray(docstring const & name, int m, int n) + : InsetMathGrid(m, n), name_(name) +{} + + +InsetMathAMSArray::InsetMathAMSArray(docstring const & name) + : InsetMathGrid(1, 1), name_(name) +{} + + +auto_ptr InsetMathAMSArray::doClone() const +{ + return auto_ptr(new InsetMathAMSArray(*this)); +} + + +char const * InsetMathAMSArray::name_left() const +{ + if (name_ == "bmatrix") + return "["; + if (name_ == "Bmatrix") + return "{"; + if (name_ == "vmatrix") + return "|"; + if (name_ == "Vmatrix") + return "Vert"; + if (name_ == "pmatrix") + return "("; + return "."; +} + + +char const * InsetMathAMSArray::name_right() const +{ + if (name_ == "bmatrix") + return "]"; + if (name_ == "Bmatrix") + return "}"; + if (name_ == "vmatrix") + return "|"; + if (name_ == "Vmatrix") + return "Vert"; + if (name_ == "pmatrix") + return ")"; + return "."; +} + + +bool InsetMathAMSArray::metrics(MetricsInfo & mi, Dimension & dim) const +{ + ArrayChanger dummy(mi.base); + InsetMathGrid::metrics(mi, dim); + dim.wid += 14; + bool const changed = dim_ != dim; + dim_ = dim; + return changed; +} + + +void InsetMathAMSArray::draw(PainterInfo & pi, int x, int y) const +{ + int const yy = y - dim_.ascent(); + // Drawing the deco after an ArrayChanger does not work + mathed_draw_deco(pi, x + 1, yy, 5, dim_.height(), from_ascii(name_left())); + mathed_draw_deco(pi, x + dim_.width() - 8, yy, 5, dim_.height(), from_ascii(name_right())); + ArrayChanger dummy(pi.base); + InsetMathGrid::drawWithMargin(pi, x, y, 6, 8); +} + + +bool InsetMathAMSArray::getStatus(LCursor & cur, FuncRequest const & cmd, + FuncStatus & flag) const +{ + switch (cmd.action) { + case LFUN_TABULAR_FEATURE: { + docstring const & s = cmd.argument(); + if (s == "add-vline-left" || s == "add-vline-right") { + flag.message(bformat( + from_utf8(N_("Can't add vertical grid lines in '%1$s'")), name_)); + flag.enabled(false); + return true; + } + return InsetMathGrid::getStatus(cur, cmd, flag); + } + default: + return InsetMathGrid::getStatus(cur, cmd, flag); + } +} + + +void InsetMathAMSArray::write(WriteStream & os) const +{ + os << "\\begin{" << name_ << '}'; + InsetMathGrid::write(os); + os << "\\end{" << name_ << '}'; +} + + +void InsetMathAMSArray::infoize(odocstream & os) const +{ + docstring name = name_; + name[0] = support::uppercase(name[0]); + os << name << ' '; +} + + +void InsetMathAMSArray::normalize(NormalStream & os) const +{ + os << '[' << name_ << ' '; + InsetMathGrid::normalize(os); + os << ']'; +} + + +void InsetMathAMSArray::validate(LaTeXFeatures & features) const +{ + features.require("amsmath"); + InsetMathGrid::validate(features); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathArray.C b/src/mathed/InsetMathArray.C deleted file mode 100644 index 8732f50c9c..0000000000 --- a/src/mathed/InsetMathArray.C +++ /dev/null @@ -1,153 +0,0 @@ -/** - * \file InsetMathArray.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "LaTeXFeatures.h" -#include "InsetMathArray.h" -#include "MathData.h" -#include "MathParser.h" -#include "MathStream.h" - -#include "support/lstrings.h" - -#include -#include - - -namespace lyx { - -using std::getline; -using std::auto_ptr; -using std::istringstream; -using std::istream_iterator; -using std::vector; -using std::string; - - -InsetMathArray::InsetMathArray(docstring const & name, int m, int n) - : InsetMathGrid(m, n), name_(name) -{} - - -InsetMathArray::InsetMathArray(docstring const & name, int m, int n, - char valign, docstring const & halign) - : InsetMathGrid(m, n, valign, halign), name_(name) -{} - - -InsetMathArray::InsetMathArray(docstring const & name, char valign, - docstring const & halign) - : InsetMathGrid(valign, halign), name_(name) -{} - - -InsetMathArray::InsetMathArray(docstring const & name, docstring const & str) - : InsetMathGrid(1, 1), name_(name) -{ - vector< vector > dat; - istringstream is(to_utf8(str)); - string line; - while (getline(is, line)) { - istringstream ls(line); - typedef istream_iterator iter; - vector v = vector(iter(ls), iter()); - if (v.size()) - dat.push_back(v); - } - - for (row_type row = 1; row < dat.size(); ++row) - addRow(0); - for (col_type col = 1; col < dat[0].size(); ++col) - addCol(0); - for (row_type row = 0; row < dat.size(); ++row) - for (col_type col = 0; col < dat[0].size(); ++col) - mathed_parse_cell(cell(index(row, col)), from_utf8(dat[row][col])); -} - - -auto_ptr InsetMathArray::doClone() const -{ - return auto_ptr(new InsetMathArray(*this)); -} - - -bool InsetMathArray::metrics(MetricsInfo & mi, Dimension & dim) const -{ - ArrayChanger dummy(mi.base); - InsetMathGrid::metrics(mi, dim); - dim.wid += 6; - bool const changed = dim_ != dim; - dim_ = dim; - return changed; -} - - -void InsetMathArray::draw(PainterInfo & pi, int x, int y) const -{ - setPosCache(pi, x, y); - ArrayChanger dummy(pi.base); - InsetMathGrid::drawWithMargin(pi, x, y, 4, 2); -} - - -void InsetMathArray::write(WriteStream & os) const -{ - if (os.fragile()) - os << "\\protect"; - os << "\\begin{" << name_ << '}'; - - if (v_align_ == 't' || v_align_ == 'b') - os << '[' << char(v_align_) << ']'; - os << '{' << halign() << "}\n"; - - InsetMathGrid::write(os); - - if (os.fragile()) - os << "\\protect"; - os << "\\end{" << name_ << '}'; - // adding a \n here is bad if the array is the last item - // in an \eqnarray... -} - - -void InsetMathArray::infoize(odocstream & os) const -{ - docstring name = name_; - name[0] = support::uppercase(name[0]); - os << name << ' '; -} - - -void InsetMathArray::normalize(NormalStream & os) const -{ - os << '[' << name_ << ' '; - InsetMathGrid::normalize(os); - os << ']'; -} - - -void InsetMathArray::maple(MapleStream & os) const -{ - os << "array("; - InsetMathGrid::maple(os); - os << ')'; -} - - -void InsetMathArray::validate(LaTeXFeatures & features) const -{ - if (name_ == "subarray") - features.require("amsmath"); - InsetMathGrid::validate(features); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathArray.cpp b/src/mathed/InsetMathArray.cpp new file mode 100644 index 0000000000..8732f50c9c --- /dev/null +++ b/src/mathed/InsetMathArray.cpp @@ -0,0 +1,153 @@ +/** + * \file InsetMathArray.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "LaTeXFeatures.h" +#include "InsetMathArray.h" +#include "MathData.h" +#include "MathParser.h" +#include "MathStream.h" + +#include "support/lstrings.h" + +#include +#include + + +namespace lyx { + +using std::getline; +using std::auto_ptr; +using std::istringstream; +using std::istream_iterator; +using std::vector; +using std::string; + + +InsetMathArray::InsetMathArray(docstring const & name, int m, int n) + : InsetMathGrid(m, n), name_(name) +{} + + +InsetMathArray::InsetMathArray(docstring const & name, int m, int n, + char valign, docstring const & halign) + : InsetMathGrid(m, n, valign, halign), name_(name) +{} + + +InsetMathArray::InsetMathArray(docstring const & name, char valign, + docstring const & halign) + : InsetMathGrid(valign, halign), name_(name) +{} + + +InsetMathArray::InsetMathArray(docstring const & name, docstring const & str) + : InsetMathGrid(1, 1), name_(name) +{ + vector< vector > dat; + istringstream is(to_utf8(str)); + string line; + while (getline(is, line)) { + istringstream ls(line); + typedef istream_iterator iter; + vector v = vector(iter(ls), iter()); + if (v.size()) + dat.push_back(v); + } + + for (row_type row = 1; row < dat.size(); ++row) + addRow(0); + for (col_type col = 1; col < dat[0].size(); ++col) + addCol(0); + for (row_type row = 0; row < dat.size(); ++row) + for (col_type col = 0; col < dat[0].size(); ++col) + mathed_parse_cell(cell(index(row, col)), from_utf8(dat[row][col])); +} + + +auto_ptr InsetMathArray::doClone() const +{ + return auto_ptr(new InsetMathArray(*this)); +} + + +bool InsetMathArray::metrics(MetricsInfo & mi, Dimension & dim) const +{ + ArrayChanger dummy(mi.base); + InsetMathGrid::metrics(mi, dim); + dim.wid += 6; + bool const changed = dim_ != dim; + dim_ = dim; + return changed; +} + + +void InsetMathArray::draw(PainterInfo & pi, int x, int y) const +{ + setPosCache(pi, x, y); + ArrayChanger dummy(pi.base); + InsetMathGrid::drawWithMargin(pi, x, y, 4, 2); +} + + +void InsetMathArray::write(WriteStream & os) const +{ + if (os.fragile()) + os << "\\protect"; + os << "\\begin{" << name_ << '}'; + + if (v_align_ == 't' || v_align_ == 'b') + os << '[' << char(v_align_) << ']'; + os << '{' << halign() << "}\n"; + + InsetMathGrid::write(os); + + if (os.fragile()) + os << "\\protect"; + os << "\\end{" << name_ << '}'; + // adding a \n here is bad if the array is the last item + // in an \eqnarray... +} + + +void InsetMathArray::infoize(odocstream & os) const +{ + docstring name = name_; + name[0] = support::uppercase(name[0]); + os << name << ' '; +} + + +void InsetMathArray::normalize(NormalStream & os) const +{ + os << '[' << name_ << ' '; + InsetMathGrid::normalize(os); + os << ']'; +} + + +void InsetMathArray::maple(MapleStream & os) const +{ + os << "array("; + InsetMathGrid::maple(os); + os << ')'; +} + + +void InsetMathArray::validate(LaTeXFeatures & features) const +{ + if (name_ == "subarray") + features.require("amsmath"); + InsetMathGrid::validate(features); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathBig.C b/src/mathed/InsetMathBig.C deleted file mode 100644 index e56acca078..0000000000 --- a/src/mathed/InsetMathBig.C +++ /dev/null @@ -1,130 +0,0 @@ -/** - * \file InsetMathBig.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathBig.h" -#include "MathSupport.h" -#include "MathStream.h" -#include "MathStream.h" - -#include "frontends/FontMetrics.h" - -#include "support/lstrings.h" - - -namespace lyx { - -using std::auto_ptr; - - -InsetMathBig::InsetMathBig(docstring const & name, docstring const & delim) - : name_(name), delim_(delim) -{} - - -docstring InsetMathBig::name() const -{ - return name_; -} - - -auto_ptr InsetMathBig::doClone() const -{ - return auto_ptr(new InsetMathBig(*this)); -} - - -InsetMathBig::size_type InsetMathBig::size() const -{ - // order: big Big bigg Bigg biggg Biggg - // 0 1 2 3 4 5 - return name_[0] == 'B' ? - 2 * (name_.size() - 4) + 1: - 2 * (name_.size() - 4); -} - - -double InsetMathBig::increase() const -{ - // The formula used in amsmath.sty is - // 1.2 * (1.0 + size() * 0.5) - 1.0. - // We use a smaller step and a bigger offset because our base size - // is different. - return (size() + 1) * 0.3; -} - - -bool InsetMathBig::metrics(MetricsInfo & mi, Dimension & dim) const -{ - double const h = theFontMetrics(mi.base.font).ascent('I'); - double const f = increase(); - dim.wid = 6; - dim.asc = int(h + f * h); - dim.des = int(f * h); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathBig::draw(PainterInfo & pi, int x, int y) const -{ - // mathed_draw_deco does not use the leading backslash, so remove it - // (but don't use ltrim if this is the backslash delimiter). - // Replace \| by \Vert (equivalent in LaTeX), since mathed_draw_deco - // would treat it as |. - docstring const delim = (delim_ == "\\|") ? from_ascii("Vert") : - (delim_ == "\\\\") ? from_ascii("\\") : support::ltrim(delim_, "\\"); - mathed_draw_deco(pi, x + 1, y - dim_.ascent(), 4, dim_.height(), - delim); - setPosCache(pi, x, y); -} - - -void InsetMathBig::write(WriteStream & os) const -{ - os << '\\' << name_ << delim_; - if (delim_[0] == '\\') - os.pendingSpace(true); -} - - -void InsetMathBig::normalize(NormalStream & os) const -{ - os << '[' << name_ << ' ' << delim_ << ']'; -} - - -void InsetMathBig::infoize2(odocstream & os) const -{ - os << name_; -} - - -bool InsetMathBig::isBigInsetDelim(docstring const & delim) -{ - // mathed_draw_deco must handle these - static char const * const delimiters[] = { - "(", ")", "\\{", "\\}", "\\lbrace", "\\rbrace", "[", "]", - "|", "/", "\\slash", "\\|", "\\vert", "\\Vert", "'", - "\\\\", "\\backslash", - "\\langle", "\\lceil", "\\lfloor", - "\\rangle", "\\rceil", "\\rfloor", - "\\downarrow", "\\Downarrow", - "\\uparrow", "\\Uparrow", - "\\updownarrow", "\\Updownarrow", "" - }; - return support::findToken(delimiters, to_utf8(delim)) >= 0; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathBig.cpp b/src/mathed/InsetMathBig.cpp new file mode 100644 index 0000000000..e56acca078 --- /dev/null +++ b/src/mathed/InsetMathBig.cpp @@ -0,0 +1,130 @@ +/** + * \file InsetMathBig.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathBig.h" +#include "MathSupport.h" +#include "MathStream.h" +#include "MathStream.h" + +#include "frontends/FontMetrics.h" + +#include "support/lstrings.h" + + +namespace lyx { + +using std::auto_ptr; + + +InsetMathBig::InsetMathBig(docstring const & name, docstring const & delim) + : name_(name), delim_(delim) +{} + + +docstring InsetMathBig::name() const +{ + return name_; +} + + +auto_ptr InsetMathBig::doClone() const +{ + return auto_ptr(new InsetMathBig(*this)); +} + + +InsetMathBig::size_type InsetMathBig::size() const +{ + // order: big Big bigg Bigg biggg Biggg + // 0 1 2 3 4 5 + return name_[0] == 'B' ? + 2 * (name_.size() - 4) + 1: + 2 * (name_.size() - 4); +} + + +double InsetMathBig::increase() const +{ + // The formula used in amsmath.sty is + // 1.2 * (1.0 + size() * 0.5) - 1.0. + // We use a smaller step and a bigger offset because our base size + // is different. + return (size() + 1) * 0.3; +} + + +bool InsetMathBig::metrics(MetricsInfo & mi, Dimension & dim) const +{ + double const h = theFontMetrics(mi.base.font).ascent('I'); + double const f = increase(); + dim.wid = 6; + dim.asc = int(h + f * h); + dim.des = int(f * h); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathBig::draw(PainterInfo & pi, int x, int y) const +{ + // mathed_draw_deco does not use the leading backslash, so remove it + // (but don't use ltrim if this is the backslash delimiter). + // Replace \| by \Vert (equivalent in LaTeX), since mathed_draw_deco + // would treat it as |. + docstring const delim = (delim_ == "\\|") ? from_ascii("Vert") : + (delim_ == "\\\\") ? from_ascii("\\") : support::ltrim(delim_, "\\"); + mathed_draw_deco(pi, x + 1, y - dim_.ascent(), 4, dim_.height(), + delim); + setPosCache(pi, x, y); +} + + +void InsetMathBig::write(WriteStream & os) const +{ + os << '\\' << name_ << delim_; + if (delim_[0] == '\\') + os.pendingSpace(true); +} + + +void InsetMathBig::normalize(NormalStream & os) const +{ + os << '[' << name_ << ' ' << delim_ << ']'; +} + + +void InsetMathBig::infoize2(odocstream & os) const +{ + os << name_; +} + + +bool InsetMathBig::isBigInsetDelim(docstring const & delim) +{ + // mathed_draw_deco must handle these + static char const * const delimiters[] = { + "(", ")", "\\{", "\\}", "\\lbrace", "\\rbrace", "[", "]", + "|", "/", "\\slash", "\\|", "\\vert", "\\Vert", "'", + "\\\\", "\\backslash", + "\\langle", "\\lceil", "\\lfloor", + "\\rangle", "\\rceil", "\\rfloor", + "\\downarrow", "\\Downarrow", + "\\uparrow", "\\Uparrow", + "\\updownarrow", "\\Updownarrow", "" + }; + return support::findToken(delimiters, to_utf8(delim)) >= 0; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathBinom.C b/src/mathed/InsetMathBinom.C deleted file mode 100644 index 0a08e7bea3..0000000000 --- a/src/mathed/InsetMathBinom.C +++ /dev/null @@ -1,97 +0,0 @@ -/** - * \file InsetMathBinom.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathBinom.h" -#include "MathData.h" -#include "MathSupport.h" -#include "MathStream.h" - - -namespace lyx { - - -using std::max; -using std::auto_ptr; - - -InsetMathBinom::InsetMathBinom(bool choose) - : choose_(choose) -{} - - -auto_ptr InsetMathBinom::doClone() const -{ - return auto_ptr(new InsetMathBinom(*this)); -} - - -int InsetMathBinom::dw() const -{ - int w = dim_.height() / 5; - if (w > 15) - w = 15; - if (w < 6) - w = 6; - return w; -} - - -bool InsetMathBinom::metrics(MetricsInfo & mi, Dimension & dim) const -{ - ScriptChanger dummy(mi.base); - cell(0).metrics(mi); - cell(1).metrics(mi); - dim.asc = cell(0).height() + 4 + 5; - dim.des = cell(1).height() + 4 - 5; - dim.wid = max(cell(0).width(), cell(1).width()) + 2 * dw() + 4; - metricsMarkers2(dim); - bool const changed = dim_ != dim; - dim_ = dim; - return changed; -} - - -void InsetMathBinom::draw(PainterInfo & pi, int x, int y) const -{ - int m = x + dim_.width() / 2; - ScriptChanger dummy(pi.base); - cell(0).draw(pi, m - cell(0).width() / 2, y - cell(0).descent() - 3 - 5); - cell(1).draw(pi, m - cell(1).width() / 2, y + cell(1).ascent() + 3 - 5); - mathed_draw_deco(pi, x, y - dim_.ascent(), dw(), dim_.height(), from_ascii("(")); - mathed_draw_deco(pi, x + dim_.width() - dw(), y - dim_.ascent(), - dw(), dim_.height(), from_ascii(")")); - drawMarkers2(pi, x, y); -} - - -bool InsetMathBinom::extraBraces() const -{ - return choose_; -} - - -void InsetMathBinom::write(WriteStream & os) const -{ - if (choose_) - os << '{' << cell(0) << " \\choose " << cell(1) << '}'; - else - os << "\\binom{" << cell(0) << "}{" << cell(1) << '}'; -} - - -void InsetMathBinom::normalize(NormalStream & os) const -{ - os << "[binom " << cell(0) << ' ' << cell(1) << ']'; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathBinom.cpp b/src/mathed/InsetMathBinom.cpp new file mode 100644 index 0000000000..0a08e7bea3 --- /dev/null +++ b/src/mathed/InsetMathBinom.cpp @@ -0,0 +1,97 @@ +/** + * \file InsetMathBinom.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathBinom.h" +#include "MathData.h" +#include "MathSupport.h" +#include "MathStream.h" + + +namespace lyx { + + +using std::max; +using std::auto_ptr; + + +InsetMathBinom::InsetMathBinom(bool choose) + : choose_(choose) +{} + + +auto_ptr InsetMathBinom::doClone() const +{ + return auto_ptr(new InsetMathBinom(*this)); +} + + +int InsetMathBinom::dw() const +{ + int w = dim_.height() / 5; + if (w > 15) + w = 15; + if (w < 6) + w = 6; + return w; +} + + +bool InsetMathBinom::metrics(MetricsInfo & mi, Dimension & dim) const +{ + ScriptChanger dummy(mi.base); + cell(0).metrics(mi); + cell(1).metrics(mi); + dim.asc = cell(0).height() + 4 + 5; + dim.des = cell(1).height() + 4 - 5; + dim.wid = max(cell(0).width(), cell(1).width()) + 2 * dw() + 4; + metricsMarkers2(dim); + bool const changed = dim_ != dim; + dim_ = dim; + return changed; +} + + +void InsetMathBinom::draw(PainterInfo & pi, int x, int y) const +{ + int m = x + dim_.width() / 2; + ScriptChanger dummy(pi.base); + cell(0).draw(pi, m - cell(0).width() / 2, y - cell(0).descent() - 3 - 5); + cell(1).draw(pi, m - cell(1).width() / 2, y + cell(1).ascent() + 3 - 5); + mathed_draw_deco(pi, x, y - dim_.ascent(), dw(), dim_.height(), from_ascii("(")); + mathed_draw_deco(pi, x + dim_.width() - dw(), y - dim_.ascent(), + dw(), dim_.height(), from_ascii(")")); + drawMarkers2(pi, x, y); +} + + +bool InsetMathBinom::extraBraces() const +{ + return choose_; +} + + +void InsetMathBinom::write(WriteStream & os) const +{ + if (choose_) + os << '{' << cell(0) << " \\choose " << cell(1) << '}'; + else + os << "\\binom{" << cell(0) << "}{" << cell(1) << '}'; +} + + +void InsetMathBinom::normalize(NormalStream & os) const +{ + os << "[binom " << cell(0) << ' ' << cell(1) << ']'; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathBoldSymbol.C b/src/mathed/InsetMathBoldSymbol.C deleted file mode 100644 index 1d7c6f6760..0000000000 --- a/src/mathed/InsetMathBoldSymbol.C +++ /dev/null @@ -1,89 +0,0 @@ -/** - * \file InsetMathBoldSymbol.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathBoldSymbol.h" -#include "MathStream.h" -#include "MathData.h" -#include "LaTeXFeatures.h" -#include "support/std_ostream.h" - - -namespace lyx { - -using std::auto_ptr; - - -InsetMathBoldSymbol::InsetMathBoldSymbol() - : InsetMathNest(1) -{} - - -auto_ptr InsetMathBoldSymbol::doClone() const -{ - return auto_ptr(new InsetMathBoldSymbol(*this)); -} - - -bool InsetMathBoldSymbol::metrics(MetricsInfo & mi, Dimension & dim) const -{ - //FontSetChanger dummy(mi.base, "mathbf"); - cell(0).metrics(mi, dim); - metricsMarkers(dim); - ++dim.wid; // for 'double stroke' - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathBoldSymbol::draw(PainterInfo & pi, int x, int y) const -{ - //FontSetChanger dummy(pi.base, "mathbf"); - cell(0).draw(pi, x + 1, y); - cell(0).draw(pi, x + 2, y); - drawMarkers(pi, x, y); -} - - -void InsetMathBoldSymbol::metricsT(TextMetricsInfo const & mi, Dimension & /*dim*/) const -{ - cell(0).metricsT(mi, dim_); -} - - -void InsetMathBoldSymbol::drawT(TextPainter & pain, int x, int y) const -{ - cell(0).drawT(pain, x, y); -} - - -void InsetMathBoldSymbol::validate(LaTeXFeatures & features) const -{ - InsetMathNest::validate(features); - features.require("amssymb"); -} - - -void InsetMathBoldSymbol::write(WriteStream & os) const -{ - os << "\\boldsymbol{" << cell(0) << "}"; -} - - -void InsetMathBoldSymbol::infoize(odocstream & os) const -{ - os << "Boldsymbol "; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathBoldSymbol.cpp b/src/mathed/InsetMathBoldSymbol.cpp new file mode 100644 index 0000000000..1d7c6f6760 --- /dev/null +++ b/src/mathed/InsetMathBoldSymbol.cpp @@ -0,0 +1,89 @@ +/** + * \file InsetMathBoldSymbol.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathBoldSymbol.h" +#include "MathStream.h" +#include "MathData.h" +#include "LaTeXFeatures.h" +#include "support/std_ostream.h" + + +namespace lyx { + +using std::auto_ptr; + + +InsetMathBoldSymbol::InsetMathBoldSymbol() + : InsetMathNest(1) +{} + + +auto_ptr InsetMathBoldSymbol::doClone() const +{ + return auto_ptr(new InsetMathBoldSymbol(*this)); +} + + +bool InsetMathBoldSymbol::metrics(MetricsInfo & mi, Dimension & dim) const +{ + //FontSetChanger dummy(mi.base, "mathbf"); + cell(0).metrics(mi, dim); + metricsMarkers(dim); + ++dim.wid; // for 'double stroke' + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathBoldSymbol::draw(PainterInfo & pi, int x, int y) const +{ + //FontSetChanger dummy(pi.base, "mathbf"); + cell(0).draw(pi, x + 1, y); + cell(0).draw(pi, x + 2, y); + drawMarkers(pi, x, y); +} + + +void InsetMathBoldSymbol::metricsT(TextMetricsInfo const & mi, Dimension & /*dim*/) const +{ + cell(0).metricsT(mi, dim_); +} + + +void InsetMathBoldSymbol::drawT(TextPainter & pain, int x, int y) const +{ + cell(0).drawT(pain, x, y); +} + + +void InsetMathBoldSymbol::validate(LaTeXFeatures & features) const +{ + InsetMathNest::validate(features); + features.require("amssymb"); +} + + +void InsetMathBoldSymbol::write(WriteStream & os) const +{ + os << "\\boldsymbol{" << cell(0) << "}"; +} + + +void InsetMathBoldSymbol::infoize(odocstream & os) const +{ + os << "Boldsymbol "; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathBox.C b/src/mathed/InsetMathBox.C deleted file mode 100644 index 0447e84467..0000000000 --- a/src/mathed/InsetMathBox.C +++ /dev/null @@ -1,77 +0,0 @@ -/** - * \file InsetMathBox.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathBox.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathStream.h" -#include "support/std_ostream.h" - - -namespace lyx { - -using std::string; -using std::auto_ptr; - - -InsetMathBox::InsetMathBox(docstring const & name) - : InsetMathNest(1), name_(name) -{} - - -auto_ptr InsetMathBox::doClone() const -{ - return auto_ptr(new InsetMathBox(*this)); -} - - -void InsetMathBox::write(WriteStream & os) const -{ - os << '\\' << name_ << '{' << cell(0) << '}'; -} - - -void InsetMathBox::normalize(NormalStream & os) const -{ - os << '[' << name_ << ' '; - //text_->write(buffer(), os); - os << "] "; -} - - -bool InsetMathBox::metrics(MetricsInfo & mi, Dimension & dim) const -{ - FontSetChanger dummy(mi.base, "textnormal"); - cell(0).metrics(mi, dim); - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathBox::draw(PainterInfo & pi, int x, int y) const -{ - FontSetChanger dummy(pi.base, "textnormal"); - cell(0).draw(pi, x, y); - drawMarkers(pi, x, y); -} - - -void InsetMathBox::infoize(odocstream & os) const -{ - os << "Box: " << name_; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathBox.cpp b/src/mathed/InsetMathBox.cpp new file mode 100644 index 0000000000..0447e84467 --- /dev/null +++ b/src/mathed/InsetMathBox.cpp @@ -0,0 +1,77 @@ +/** + * \file InsetMathBox.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathBox.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathStream.h" +#include "support/std_ostream.h" + + +namespace lyx { + +using std::string; +using std::auto_ptr; + + +InsetMathBox::InsetMathBox(docstring const & name) + : InsetMathNest(1), name_(name) +{} + + +auto_ptr InsetMathBox::doClone() const +{ + return auto_ptr(new InsetMathBox(*this)); +} + + +void InsetMathBox::write(WriteStream & os) const +{ + os << '\\' << name_ << '{' << cell(0) << '}'; +} + + +void InsetMathBox::normalize(NormalStream & os) const +{ + os << '[' << name_ << ' '; + //text_->write(buffer(), os); + os << "] "; +} + + +bool InsetMathBox::metrics(MetricsInfo & mi, Dimension & dim) const +{ + FontSetChanger dummy(mi.base, "textnormal"); + cell(0).metrics(mi, dim); + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathBox::draw(PainterInfo & pi, int x, int y) const +{ + FontSetChanger dummy(pi.base, "textnormal"); + cell(0).draw(pi, x, y); + drawMarkers(pi, x, y); +} + + +void InsetMathBox::infoize(odocstream & os) const +{ + os << "Box: " << name_; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathBoxed.C b/src/mathed/InsetMathBoxed.C deleted file mode 100644 index 2ff48888f7..0000000000 --- a/src/mathed/InsetMathBoxed.C +++ /dev/null @@ -1,83 +0,0 @@ -/** - * \file InsetMathBoxed.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathBoxed.h" -#include "MathData.h" -#include "MathStream.h" -#include "LaTeXFeatures.h" -#include "LColor.h" - -#include "support/std_ostream.h" -#include "frontends/Painter.h" - - -namespace lyx { - -using std::auto_ptr; - - -InsetMathBoxed::InsetMathBoxed() - : InsetMathNest(1) -{} - - -auto_ptr InsetMathBoxed::doClone() const -{ - return auto_ptr(new InsetMathBoxed(*this)); -} - - -bool InsetMathBoxed::metrics(MetricsInfo & mi, Dimension & dim) const -{ - cell(0).metrics(mi, dim); - metricsMarkers2(dim, 3); // 1 pixel space, 1 frame, 1 space - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathBoxed::draw(PainterInfo & pi, int x, int y) const -{ - pi.pain.rectangle(x + 1, y - dim_.ascent() + 1, - dim_.width() - 2, dim_.height() - 2, LColor::foreground); - cell(0).draw(pi, x + 3, y); - setPosCache(pi, x, y); -} - - -void InsetMathBoxed::write(WriteStream & os) const -{ - os << "\\boxed{" << cell(0) << '}'; -} - - -void InsetMathBoxed::normalize(NormalStream & os) const -{ - os << "[boxed " << cell(0) << ']'; -} - - -void InsetMathBoxed::infoize(odocstream & os) const -{ - os << "Boxed: "; -} - - -void InsetMathBoxed::validate(LaTeXFeatures & features) const -{ - features.require("amsmath"); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathBoxed.cpp b/src/mathed/InsetMathBoxed.cpp new file mode 100644 index 0000000000..2ff48888f7 --- /dev/null +++ b/src/mathed/InsetMathBoxed.cpp @@ -0,0 +1,83 @@ +/** + * \file InsetMathBoxed.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathBoxed.h" +#include "MathData.h" +#include "MathStream.h" +#include "LaTeXFeatures.h" +#include "LColor.h" + +#include "support/std_ostream.h" +#include "frontends/Painter.h" + + +namespace lyx { + +using std::auto_ptr; + + +InsetMathBoxed::InsetMathBoxed() + : InsetMathNest(1) +{} + + +auto_ptr InsetMathBoxed::doClone() const +{ + return auto_ptr(new InsetMathBoxed(*this)); +} + + +bool InsetMathBoxed::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(0).metrics(mi, dim); + metricsMarkers2(dim, 3); // 1 pixel space, 1 frame, 1 space + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathBoxed::draw(PainterInfo & pi, int x, int y) const +{ + pi.pain.rectangle(x + 1, y - dim_.ascent() + 1, + dim_.width() - 2, dim_.height() - 2, LColor::foreground); + cell(0).draw(pi, x + 3, y); + setPosCache(pi, x, y); +} + + +void InsetMathBoxed::write(WriteStream & os) const +{ + os << "\\boxed{" << cell(0) << '}'; +} + + +void InsetMathBoxed::normalize(NormalStream & os) const +{ + os << "[boxed " << cell(0) << ']'; +} + + +void InsetMathBoxed::infoize(odocstream & os) const +{ + os << "Boxed: "; +} + + +void InsetMathBoxed::validate(LaTeXFeatures & features) const +{ + features.require("amsmath"); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathBrace.C b/src/mathed/InsetMathBrace.C deleted file mode 100644 index 54b00d89c3..0000000000 --- a/src/mathed/InsetMathBrace.C +++ /dev/null @@ -1,117 +0,0 @@ -/** - * \file InsetMathBrace.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathBrace.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathSupport.h" -#include "LColor.h" - -#include "frontends/FontMetrics.h" -#include "frontends/Painter.h" - -#include "support/std_ostream.h" - -namespace lyx { - -using std::max; -using std::auto_ptr; - - -InsetMathBrace::InsetMathBrace() - : InsetMathNest(1) -{} - - -InsetMathBrace::InsetMathBrace(MathArray const & ar) - : InsetMathNest(1) -{ - cell(0) = ar; -} - - -auto_ptr InsetMathBrace::doClone() const -{ - return auto_ptr(new InsetMathBrace(*this)); -} - - -bool InsetMathBrace::metrics(MetricsInfo & mi, Dimension & dim) const -{ - cell(0).metrics(mi); - Dimension t = theFontMetrics(mi.base.font).dimension('{'); - dim.asc = max(cell(0).ascent(), t.asc); - dim.des = max(cell(0).descent(), t.des); - dim.wid = cell(0).width() + 2 * t.wid; - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathBrace::draw(PainterInfo & pi, int x, int y) const -{ - LyXFont font = pi.base.font; - font.setColor(LColor::latex); - Dimension t = theFontMetrics(font).dimension('{'); - pi.pain.text(x, y, '{', font); - cell(0).draw(pi, x + t.wid, y); - pi.pain.text(x + t.wid + cell(0).width(), y, '}', font); - drawMarkers(pi, x, y); -} - - -void InsetMathBrace::write(WriteStream & os) const -{ - os << '{' << cell(0) << '}'; -} - - -void InsetMathBrace::normalize(NormalStream & os) const -{ - os << "[block " << cell(0) << ']'; -} - - -void InsetMathBrace::maple(MapleStream & os) const -{ - os << cell(0); -} - - -void InsetMathBrace::octave(OctaveStream & os) const -{ - os << cell(0); -} - - -void InsetMathBrace::mathmlize(MathStream & os) const -{ - os << MTag("mrow") << cell(0) << ETag("mrow"); -} - - -void InsetMathBrace::mathematica(MathematicaStream & os) const -{ - os << cell(0); -} - - -void InsetMathBrace::infoize(odocstream & os) const -{ - os << "Nested Block: "; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathBrace.cpp b/src/mathed/InsetMathBrace.cpp new file mode 100644 index 0000000000..54b00d89c3 --- /dev/null +++ b/src/mathed/InsetMathBrace.cpp @@ -0,0 +1,117 @@ +/** + * \file InsetMathBrace.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathBrace.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathSupport.h" +#include "LColor.h" + +#include "frontends/FontMetrics.h" +#include "frontends/Painter.h" + +#include "support/std_ostream.h" + +namespace lyx { + +using std::max; +using std::auto_ptr; + + +InsetMathBrace::InsetMathBrace() + : InsetMathNest(1) +{} + + +InsetMathBrace::InsetMathBrace(MathArray const & ar) + : InsetMathNest(1) +{ + cell(0) = ar; +} + + +auto_ptr InsetMathBrace::doClone() const +{ + return auto_ptr(new InsetMathBrace(*this)); +} + + +bool InsetMathBrace::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(0).metrics(mi); + Dimension t = theFontMetrics(mi.base.font).dimension('{'); + dim.asc = max(cell(0).ascent(), t.asc); + dim.des = max(cell(0).descent(), t.des); + dim.wid = cell(0).width() + 2 * t.wid; + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathBrace::draw(PainterInfo & pi, int x, int y) const +{ + LyXFont font = pi.base.font; + font.setColor(LColor::latex); + Dimension t = theFontMetrics(font).dimension('{'); + pi.pain.text(x, y, '{', font); + cell(0).draw(pi, x + t.wid, y); + pi.pain.text(x + t.wid + cell(0).width(), y, '}', font); + drawMarkers(pi, x, y); +} + + +void InsetMathBrace::write(WriteStream & os) const +{ + os << '{' << cell(0) << '}'; +} + + +void InsetMathBrace::normalize(NormalStream & os) const +{ + os << "[block " << cell(0) << ']'; +} + + +void InsetMathBrace::maple(MapleStream & os) const +{ + os << cell(0); +} + + +void InsetMathBrace::octave(OctaveStream & os) const +{ + os << cell(0); +} + + +void InsetMathBrace::mathmlize(MathStream & os) const +{ + os << MTag("mrow") << cell(0) << ETag("mrow"); +} + + +void InsetMathBrace::mathematica(MathematicaStream & os) const +{ + os << cell(0); +} + + +void InsetMathBrace::infoize(odocstream & os) const +{ + os << "Nested Block: "; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathCases.C b/src/mathed/InsetMathCases.C deleted file mode 100644 index 86886299ba..0000000000 --- a/src/mathed/InsetMathCases.C +++ /dev/null @@ -1,150 +0,0 @@ -/** - * \file InsetMathCases.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathCases.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathSupport.h" -#include "FuncStatus.h" -#include "LaTeXFeatures.h" -#include "support/std_ostream.h" -#include "cursor.h" -#include "funcrequest.h" -#include "gettext.h" -#include "undo.h" - -#include "support/lstrings.h" - - -namespace lyx { - -using support::bformat; - -using std::endl; -using std::max; -using std::min; -using std::swap; -using std::auto_ptr; - - -InsetMathCases::InsetMathCases(row_type n) - : InsetMathGrid(2, n, 'c', from_ascii("ll")) -{} - - -auto_ptr InsetMathCases::doClone() const -{ - return auto_ptr(new InsetMathCases(*this)); -} - - -bool InsetMathCases::metrics(MetricsInfo & mi, Dimension & dim) const -{ - dim = dim_; - InsetMathGrid::metrics(mi); - dim_.wid += 8; - - if (dim_ == dim) - return false; - dim = dim_; - return true; -} - - -void InsetMathCases::draw(PainterInfo & pi, int x, int y) const -{ - mathed_draw_deco(pi, x + 1, y - dim_.ascent(), 6, dim_.height(), from_ascii("{")); - InsetMathGrid::drawWithMargin(pi, x, y, 8, 0); - setPosCache(pi, x, y); -} - - -void InsetMathCases::doDispatch(LCursor & cur, FuncRequest & cmd) -{ - //lyxerr << "*** InsetMathCases: request: " << cmd << endl; - switch (cmd.action) { - case LFUN_TABULAR_FEATURE: { - recordUndo(cur); - docstring const & s = cmd.argument(); - if (s == "add-vline-left" || s == "add-vline-right") { - cur.undispatched(); - break; - } - } - default: - InsetMathGrid::doDispatch(cur, cmd); - } -} - - -bool InsetMathCases::getStatus(LCursor & cur, FuncRequest const & cmd, - FuncStatus & flag) const -{ - switch (cmd.action) { - case LFUN_TABULAR_FEATURE: { - docstring const & s = cmd.argument(); - if (s == "add-vline-left" || s == "add-vline-right") { - flag.enabled(false); - flag.message(bformat( - from_utf8(N_("No vertical grid lines in '%1$s'")), - s)); - return true; - } - } - default: - return InsetMathGrid::getStatus(cur, cmd, flag); - } -} - - -void InsetMathCases::write(WriteStream & os) const -{ - if (os.fragile()) - os << "\\protect"; - os << "\\begin{cases}\n"; - InsetMathGrid::write(os); - if (os.fragile()) - os << "\\protect"; - os << "\\end{cases}"; -} - - -void InsetMathCases::normalize(NormalStream & os) const -{ - os << "[cases "; - InsetMathGrid::normalize(os); - os << ']'; -} - - -void InsetMathCases::maple(MapleStream & os) const -{ - os << "cases("; - InsetMathGrid::maple(os); - os << ')'; -} - - -void InsetMathCases::infoize(odocstream & os) const -{ - os << "Cases "; -} - - -void InsetMathCases::validate(LaTeXFeatures & features) const -{ - features.require("amsmath"); - InsetMathGrid::validate(features); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathCases.cpp b/src/mathed/InsetMathCases.cpp new file mode 100644 index 0000000000..86886299ba --- /dev/null +++ b/src/mathed/InsetMathCases.cpp @@ -0,0 +1,150 @@ +/** + * \file InsetMathCases.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathCases.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathSupport.h" +#include "FuncStatus.h" +#include "LaTeXFeatures.h" +#include "support/std_ostream.h" +#include "cursor.h" +#include "funcrequest.h" +#include "gettext.h" +#include "undo.h" + +#include "support/lstrings.h" + + +namespace lyx { + +using support::bformat; + +using std::endl; +using std::max; +using std::min; +using std::swap; +using std::auto_ptr; + + +InsetMathCases::InsetMathCases(row_type n) + : InsetMathGrid(2, n, 'c', from_ascii("ll")) +{} + + +auto_ptr InsetMathCases::doClone() const +{ + return auto_ptr(new InsetMathCases(*this)); +} + + +bool InsetMathCases::metrics(MetricsInfo & mi, Dimension & dim) const +{ + dim = dim_; + InsetMathGrid::metrics(mi); + dim_.wid += 8; + + if (dim_ == dim) + return false; + dim = dim_; + return true; +} + + +void InsetMathCases::draw(PainterInfo & pi, int x, int y) const +{ + mathed_draw_deco(pi, x + 1, y - dim_.ascent(), 6, dim_.height(), from_ascii("{")); + InsetMathGrid::drawWithMargin(pi, x, y, 8, 0); + setPosCache(pi, x, y); +} + + +void InsetMathCases::doDispatch(LCursor & cur, FuncRequest & cmd) +{ + //lyxerr << "*** InsetMathCases: request: " << cmd << endl; + switch (cmd.action) { + case LFUN_TABULAR_FEATURE: { + recordUndo(cur); + docstring const & s = cmd.argument(); + if (s == "add-vline-left" || s == "add-vline-right") { + cur.undispatched(); + break; + } + } + default: + InsetMathGrid::doDispatch(cur, cmd); + } +} + + +bool InsetMathCases::getStatus(LCursor & cur, FuncRequest const & cmd, + FuncStatus & flag) const +{ + switch (cmd.action) { + case LFUN_TABULAR_FEATURE: { + docstring const & s = cmd.argument(); + if (s == "add-vline-left" || s == "add-vline-right") { + flag.enabled(false); + flag.message(bformat( + from_utf8(N_("No vertical grid lines in '%1$s'")), + s)); + return true; + } + } + default: + return InsetMathGrid::getStatus(cur, cmd, flag); + } +} + + +void InsetMathCases::write(WriteStream & os) const +{ + if (os.fragile()) + os << "\\protect"; + os << "\\begin{cases}\n"; + InsetMathGrid::write(os); + if (os.fragile()) + os << "\\protect"; + os << "\\end{cases}"; +} + + +void InsetMathCases::normalize(NormalStream & os) const +{ + os << "[cases "; + InsetMathGrid::normalize(os); + os << ']'; +} + + +void InsetMathCases::maple(MapleStream & os) const +{ + os << "cases("; + InsetMathGrid::maple(os); + os << ')'; +} + + +void InsetMathCases::infoize(odocstream & os) const +{ + os << "Cases "; +} + + +void InsetMathCases::validate(LaTeXFeatures & features) const +{ + features.require("amsmath"); + InsetMathGrid::validate(features); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathChar.C b/src/mathed/InsetMathChar.C deleted file mode 100644 index 0baad6a7d5..0000000000 --- a/src/mathed/InsetMathChar.C +++ /dev/null @@ -1,179 +0,0 @@ -/** - * \file InsetMathChar.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Alejandro Aguilar Sierra - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathChar.h" -#include "MathSupport.h" -#include "MathStream.h" - -#include "debug.h" -#include "dimension.h" -#include "support/lstrings.h" -#include "TextPainter.h" - -#include "frontends/FontMetrics.h" - - -namespace lyx { - -using std::auto_ptr; - -extern bool has_math_fonts; - -namespace { - - bool isBinaryOp(char_type c) - { - return support::contains("+-<>=/*", static_cast(c)); - } - - - bool slanted(char_type c) - { - return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); - } - -} - - -InsetMathChar::InsetMathChar(char_type c) - : char_(c), kerning_(0) -{} - - - -auto_ptr InsetMathChar::doClone() const -{ - return auto_ptr(new InsetMathChar(*this)); -} - - -bool InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const -{ - if (mi.base.font == font_cache_) { - dim = dim_; - return false; - } - font_cache_ = mi.base.font; - -#if 1 - if (char_ == '=' && has_math_fonts) { - FontSetChanger dummy(mi.base, "cmr"); - dim = theFontMetrics(mi.base.font).dimension(char_); - } else if ((char_ == '>' || char_ == '<') && has_math_fonts) { - FontSetChanger dummy(mi.base, "cmm"); - dim = theFontMetrics(mi.base.font).dimension(char_); - } else if (!slanted(char_) && mi.base.fontname == "mathnormal") { - ShapeChanger dummy(mi.base.font, LyXFont::UP_SHAPE); - dim = theFontMetrics(mi.base.font).dimension(char_); - } else { - frontend::FontMetrics const & fm = theFontMetrics(mi.base.font); - dim = fm.dimension(char_); - kerning_ = fm.rbearing(char_) - dim.wid; - } - int const em = mathed_char_width(mi.base.font, 'M'); - if (isBinaryOp(char_)) - dim.wid += static_cast(0.5*em+0.5); - else if (char_ == '\'') - dim.wid += static_cast(0.1667*em+0.5); -#else - whichFont(font_, code_, mi); - dim = theFontMetrics(font_).dimension(char_); - if (isBinaryOp(char_, code_)) - dim.wid += 2 * theFontMetrics(font_).width(' '); - lyxerr << "InsetMathChar::metrics: " << dim << endl; -#endif - dim_ = dim; - return true; -} - - -void InsetMathChar::draw(PainterInfo & pi, int x, int y) const -{ - //lyxerr << "drawing '" << char_ << "' font: " << pi.base.fontname << endl; - int const em = mathed_char_width(pi.base.font, 'M'); - if (isBinaryOp(char_)) - x += static_cast(0.25*em+0.5); - else if (char_ == '\'') - x += static_cast(0.0833*em+0.5); -#if 1 - if (char_ == '=' && has_math_fonts) { - FontSetChanger dummy(pi.base, "cmr"); - pi.draw(x, y, char_); - } else if ((char_ == '>' || char_ == '<') && has_math_fonts) { - FontSetChanger dummy(pi.base, "cmm"); - pi.draw(x, y, char_); - } else if (!slanted(char_) && pi.base.fontname == "mathnormal") { - ShapeChanger dummy(pi.base.font, LyXFont::UP_SHAPE); - pi.draw(x, y, char_); - } else { - pi.draw(x, y, char_); - } -#else - drawChar(pain, font_, x, y, char_); -#endif -} - - -void InsetMathChar::metricsT(TextMetricsInfo const &, Dimension & dim) const -{ - dim.wid = 1; - dim.asc = 1; - dim.des = 0; -} - - -void InsetMathChar::drawT(TextPainter & pain, int x, int y) const -{ - //lyxerr << "drawing text '" << char_ << "' code: " << code_ << endl; - pain.draw(x, y, char_); -} - - -void InsetMathChar::write(WriteStream & os) const -{ - os.os().put(char_); -} - - -void InsetMathChar::normalize(NormalStream & os) const -{ - os << "[char "; - os.os().put(char_); - os << " mathalpha]"; -} - - -void InsetMathChar::octave(OctaveStream & os) const -{ - os.os().put(char_); -} - - -void InsetMathChar::mathmlize(MathStream & ms) const -{ - switch (char_) { - case '<': ms << "<"; break; - case '>': ms << ">"; break; - case '&': ms << "&"; break; - default: ms.os().put(char_); break; - } -} - - -bool InsetMathChar::isRelOp() const -{ - return char_ == '=' || char_ == '<' || char_ == '>'; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathChar.cpp b/src/mathed/InsetMathChar.cpp new file mode 100644 index 0000000000..0baad6a7d5 --- /dev/null +++ b/src/mathed/InsetMathChar.cpp @@ -0,0 +1,179 @@ +/** + * \file InsetMathChar.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Alejandro Aguilar Sierra + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathChar.h" +#include "MathSupport.h" +#include "MathStream.h" + +#include "debug.h" +#include "dimension.h" +#include "support/lstrings.h" +#include "TextPainter.h" + +#include "frontends/FontMetrics.h" + + +namespace lyx { + +using std::auto_ptr; + +extern bool has_math_fonts; + +namespace { + + bool isBinaryOp(char_type c) + { + return support::contains("+-<>=/*", static_cast(c)); + } + + + bool slanted(char_type c) + { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); + } + +} + + +InsetMathChar::InsetMathChar(char_type c) + : char_(c), kerning_(0) +{} + + + +auto_ptr InsetMathChar::doClone() const +{ + return auto_ptr(new InsetMathChar(*this)); +} + + +bool InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const +{ + if (mi.base.font == font_cache_) { + dim = dim_; + return false; + } + font_cache_ = mi.base.font; + +#if 1 + if (char_ == '=' && has_math_fonts) { + FontSetChanger dummy(mi.base, "cmr"); + dim = theFontMetrics(mi.base.font).dimension(char_); + } else if ((char_ == '>' || char_ == '<') && has_math_fonts) { + FontSetChanger dummy(mi.base, "cmm"); + dim = theFontMetrics(mi.base.font).dimension(char_); + } else if (!slanted(char_) && mi.base.fontname == "mathnormal") { + ShapeChanger dummy(mi.base.font, LyXFont::UP_SHAPE); + dim = theFontMetrics(mi.base.font).dimension(char_); + } else { + frontend::FontMetrics const & fm = theFontMetrics(mi.base.font); + dim = fm.dimension(char_); + kerning_ = fm.rbearing(char_) - dim.wid; + } + int const em = mathed_char_width(mi.base.font, 'M'); + if (isBinaryOp(char_)) + dim.wid += static_cast(0.5*em+0.5); + else if (char_ == '\'') + dim.wid += static_cast(0.1667*em+0.5); +#else + whichFont(font_, code_, mi); + dim = theFontMetrics(font_).dimension(char_); + if (isBinaryOp(char_, code_)) + dim.wid += 2 * theFontMetrics(font_).width(' '); + lyxerr << "InsetMathChar::metrics: " << dim << endl; +#endif + dim_ = dim; + return true; +} + + +void InsetMathChar::draw(PainterInfo & pi, int x, int y) const +{ + //lyxerr << "drawing '" << char_ << "' font: " << pi.base.fontname << endl; + int const em = mathed_char_width(pi.base.font, 'M'); + if (isBinaryOp(char_)) + x += static_cast(0.25*em+0.5); + else if (char_ == '\'') + x += static_cast(0.0833*em+0.5); +#if 1 + if (char_ == '=' && has_math_fonts) { + FontSetChanger dummy(pi.base, "cmr"); + pi.draw(x, y, char_); + } else if ((char_ == '>' || char_ == '<') && has_math_fonts) { + FontSetChanger dummy(pi.base, "cmm"); + pi.draw(x, y, char_); + } else if (!slanted(char_) && pi.base.fontname == "mathnormal") { + ShapeChanger dummy(pi.base.font, LyXFont::UP_SHAPE); + pi.draw(x, y, char_); + } else { + pi.draw(x, y, char_); + } +#else + drawChar(pain, font_, x, y, char_); +#endif +} + + +void InsetMathChar::metricsT(TextMetricsInfo const &, Dimension & dim) const +{ + dim.wid = 1; + dim.asc = 1; + dim.des = 0; +} + + +void InsetMathChar::drawT(TextPainter & pain, int x, int y) const +{ + //lyxerr << "drawing text '" << char_ << "' code: " << code_ << endl; + pain.draw(x, y, char_); +} + + +void InsetMathChar::write(WriteStream & os) const +{ + os.os().put(char_); +} + + +void InsetMathChar::normalize(NormalStream & os) const +{ + os << "[char "; + os.os().put(char_); + os << " mathalpha]"; +} + + +void InsetMathChar::octave(OctaveStream & os) const +{ + os.os().put(char_); +} + + +void InsetMathChar::mathmlize(MathStream & ms) const +{ + switch (char_) { + case '<': ms << "<"; break; + case '>': ms << ">"; break; + case '&': ms << "&"; break; + default: ms.os().put(char_); break; + } +} + + +bool InsetMathChar::isRelOp() const +{ + return char_ == '=' || char_ == '<' || char_ == '>'; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathColor.C b/src/mathed/InsetMathColor.C deleted file mode 100644 index c3358bfe34..0000000000 --- a/src/mathed/InsetMathColor.C +++ /dev/null @@ -1,105 +0,0 @@ -/** - * \file InsetMathColor.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathColor.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathSupport.h" -#include "LaTeXFeatures.h" - -#include "support/std_ostream.h" - - -namespace lyx { - -using std::auto_ptr; -using std::string; - -InsetMathColor::InsetMathColor(bool oldstyle, LColor_color const & color) - : InsetMathNest(1), oldstyle_(oldstyle), - color_(from_utf8(lcolor.getLaTeXName(color))) -{} - - -InsetMathColor::InsetMathColor(bool oldstyle, docstring const & color) - : InsetMathNest(1), oldstyle_(oldstyle), color_(color) -{} - - -auto_ptr InsetMathColor::doClone() const -{ - return auto_ptr(new InsetMathColor(*this)); -} - - -bool InsetMathColor::metrics(MetricsInfo & mi, Dimension & dim) const -{ - cell(0).metrics(mi, dim); - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathColor::draw(PainterInfo & pi, int x, int y) const -{ - LColor_color origcol = pi.base.font.color(); - pi.base.font.setColor(lcolor.getFromLaTeXName(to_utf8(color_))); - cell(0).draw(pi, x + 1, y); - pi.base.font.setColor(origcol); - drawMarkers(pi, x, y); - setPosCache(pi, x, y); -} - - -/// color "none" (reset to default) needs special treatment -static bool normalcolor(docstring const & color) -{ - return color == "none"; -} - - -void InsetMathColor::validate(LaTeXFeatures & features) const -{ - InsetMathNest::validate(features); - if (!normalcolor(color_)) - features.require("color"); -} - - -void InsetMathColor::write(WriteStream & os) const -{ - if (normalcolor(color_)) - // reset to default color inside another color inset - os << "{\\normalcolor " << cell(0) << '}'; - else if (oldstyle_) - os << "{\\color{" << color_ << '}' << cell(0) << '}'; - else - os << "\\textcolor{" << color_ << "}{" << cell(0) << '}'; -} - - -void InsetMathColor::normalize(NormalStream & os) const -{ - os << "[color " << color_ << ' ' << cell(0) << ']'; -} - - -void InsetMathColor::infoize(odocstream & os) const -{ - os << "Color: " << color_; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathColor.cpp b/src/mathed/InsetMathColor.cpp new file mode 100644 index 0000000000..c3358bfe34 --- /dev/null +++ b/src/mathed/InsetMathColor.cpp @@ -0,0 +1,105 @@ +/** + * \file InsetMathColor.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathColor.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathSupport.h" +#include "LaTeXFeatures.h" + +#include "support/std_ostream.h" + + +namespace lyx { + +using std::auto_ptr; +using std::string; + +InsetMathColor::InsetMathColor(bool oldstyle, LColor_color const & color) + : InsetMathNest(1), oldstyle_(oldstyle), + color_(from_utf8(lcolor.getLaTeXName(color))) +{} + + +InsetMathColor::InsetMathColor(bool oldstyle, docstring const & color) + : InsetMathNest(1), oldstyle_(oldstyle), color_(color) +{} + + +auto_ptr InsetMathColor::doClone() const +{ + return auto_ptr(new InsetMathColor(*this)); +} + + +bool InsetMathColor::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(0).metrics(mi, dim); + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathColor::draw(PainterInfo & pi, int x, int y) const +{ + LColor_color origcol = pi.base.font.color(); + pi.base.font.setColor(lcolor.getFromLaTeXName(to_utf8(color_))); + cell(0).draw(pi, x + 1, y); + pi.base.font.setColor(origcol); + drawMarkers(pi, x, y); + setPosCache(pi, x, y); +} + + +/// color "none" (reset to default) needs special treatment +static bool normalcolor(docstring const & color) +{ + return color == "none"; +} + + +void InsetMathColor::validate(LaTeXFeatures & features) const +{ + InsetMathNest::validate(features); + if (!normalcolor(color_)) + features.require("color"); +} + + +void InsetMathColor::write(WriteStream & os) const +{ + if (normalcolor(color_)) + // reset to default color inside another color inset + os << "{\\normalcolor " << cell(0) << '}'; + else if (oldstyle_) + os << "{\\color{" << color_ << '}' << cell(0) << '}'; + else + os << "\\textcolor{" << color_ << "}{" << cell(0) << '}'; +} + + +void InsetMathColor::normalize(NormalStream & os) const +{ + os << "[color " << color_ << ' ' << cell(0) << ']'; +} + + +void InsetMathColor::infoize(odocstream & os) const +{ + os << "Color: " << color_; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathCommand.C b/src/mathed/InsetMathCommand.C deleted file mode 100644 index 076096ef48..0000000000 --- a/src/mathed/InsetMathCommand.C +++ /dev/null @@ -1,82 +0,0 @@ -/** - * \file InsetMathCommand.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathCommand.h" -#include "MathData.h" -#include "MathStream.h" -#include "dispatchresult.h" -#include "funcrequest.h" - -#include - - -namespace lyx { - -using std::auto_ptr; -using std::string; - -CommandInset::CommandInset(docstring const & name) - : InsetMathNest(2), name_(name), set_label_(false) -{ - lock_ = true; -} - - -auto_ptr CommandInset::doClone() const -{ - return auto_ptr(new CommandInset(*this)); -} - - -bool CommandInset::metrics(MetricsInfo & mi, Dimension & dim) const -{ - if (!set_label_) { - set_label_ = true; - button_.update(screenLabel(), true); - } - button_.metrics(mi, dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -InsetBase * CommandInset::editXY(LCursor & cur, int /*x*/, int /*y*/) -{ - edit(cur, true); - return this; -} - - -void CommandInset::draw(PainterInfo & pi, int x, int y) const -{ - button_.draw(pi, x, y); - setPosCache(pi, x, y); -} - - -void CommandInset::write(WriteStream & os) const -{ - os << '\\' << name_.c_str(); - if (cell(1).size()) - os << '[' << cell(1) << ']'; - os << '{' << cell(0) << '}'; -} - - -docstring const CommandInset::screenLabel() const -{ - return name_; -} - -} // namespace lyx diff --git a/src/mathed/InsetMathCommand.cpp b/src/mathed/InsetMathCommand.cpp new file mode 100644 index 0000000000..076096ef48 --- /dev/null +++ b/src/mathed/InsetMathCommand.cpp @@ -0,0 +1,82 @@ +/** + * \file InsetMathCommand.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathCommand.h" +#include "MathData.h" +#include "MathStream.h" +#include "dispatchresult.h" +#include "funcrequest.h" + +#include + + +namespace lyx { + +using std::auto_ptr; +using std::string; + +CommandInset::CommandInset(docstring const & name) + : InsetMathNest(2), name_(name), set_label_(false) +{ + lock_ = true; +} + + +auto_ptr CommandInset::doClone() const +{ + return auto_ptr(new CommandInset(*this)); +} + + +bool CommandInset::metrics(MetricsInfo & mi, Dimension & dim) const +{ + if (!set_label_) { + set_label_ = true; + button_.update(screenLabel(), true); + } + button_.metrics(mi, dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +InsetBase * CommandInset::editXY(LCursor & cur, int /*x*/, int /*y*/) +{ + edit(cur, true); + return this; +} + + +void CommandInset::draw(PainterInfo & pi, int x, int y) const +{ + button_.draw(pi, x, y); + setPosCache(pi, x, y); +} + + +void CommandInset::write(WriteStream & os) const +{ + os << '\\' << name_.c_str(); + if (cell(1).size()) + os << '[' << cell(1) << ']'; + os << '{' << cell(0) << '}'; +} + + +docstring const CommandInset::screenLabel() const +{ + return name_; +} + +} // namespace lyx diff --git a/src/mathed/InsetMathComment.C b/src/mathed/InsetMathComment.C deleted file mode 100644 index ca0de54262..0000000000 --- a/src/mathed/InsetMathComment.C +++ /dev/null @@ -1,107 +0,0 @@ -/** - * \file InsetMathComment.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathComment.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathSupport.h" -#include "support/std_ostream.h" - - -namespace lyx { - -using std::string; -using std::auto_ptr; - - -InsetMathComment::InsetMathComment() - : InsetMathNest(1) -{} - - -InsetMathComment::InsetMathComment(docstring const & str) - : InsetMathNest(1) -{ - // FIXME UNICODE - asArray(str, cell(0)); -} - - -auto_ptr InsetMathComment::doClone() const -{ - return auto_ptr(new InsetMathComment(*this)); -} - - -bool InsetMathComment::metrics(MetricsInfo & mi, Dimension & dim) const -{ - cell(0).metrics(mi, dim); - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathComment::draw(PainterInfo & pi, int x, int y) const -{ - cell(0).draw(pi, x + 1, y); - drawMarkers(pi, x, y); -} - - -void InsetMathComment::metricsT(TextMetricsInfo const & mi, Dimension & dim) const -{ - cell(0).metricsT(mi, dim); -} - - -void InsetMathComment::drawT(TextPainter & pain, int x, int y) const -{ - cell(0).drawT(pain, x, y); -} - - -void InsetMathComment::write(WriteStream & os) const -{ - os << '%' << cell(0) << "\n"; -} - - -void InsetMathComment::maple(MapleStream & os) const -{ - os << '#' << cell(0) << "\n"; -} - - -void InsetMathComment::mathematica(MathematicaStream &) const -{} - - -void InsetMathComment::octave(OctaveStream &) const -{} - - -void InsetMathComment::mathmlize(MathStream & os) const -{ - os << MTag("comment") << cell(0) << cell(1) << ETag("comment"); -} - - -void InsetMathComment::infoize(odocstream & os) const -{ - os << "Comment"; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathComment.cpp b/src/mathed/InsetMathComment.cpp new file mode 100644 index 0000000000..ca0de54262 --- /dev/null +++ b/src/mathed/InsetMathComment.cpp @@ -0,0 +1,107 @@ +/** + * \file InsetMathComment.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathComment.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathSupport.h" +#include "support/std_ostream.h" + + +namespace lyx { + +using std::string; +using std::auto_ptr; + + +InsetMathComment::InsetMathComment() + : InsetMathNest(1) +{} + + +InsetMathComment::InsetMathComment(docstring const & str) + : InsetMathNest(1) +{ + // FIXME UNICODE + asArray(str, cell(0)); +} + + +auto_ptr InsetMathComment::doClone() const +{ + return auto_ptr(new InsetMathComment(*this)); +} + + +bool InsetMathComment::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(0).metrics(mi, dim); + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathComment::draw(PainterInfo & pi, int x, int y) const +{ + cell(0).draw(pi, x + 1, y); + drawMarkers(pi, x, y); +} + + +void InsetMathComment::metricsT(TextMetricsInfo const & mi, Dimension & dim) const +{ + cell(0).metricsT(mi, dim); +} + + +void InsetMathComment::drawT(TextPainter & pain, int x, int y) const +{ + cell(0).drawT(pain, x, y); +} + + +void InsetMathComment::write(WriteStream & os) const +{ + os << '%' << cell(0) << "\n"; +} + + +void InsetMathComment::maple(MapleStream & os) const +{ + os << '#' << cell(0) << "\n"; +} + + +void InsetMathComment::mathematica(MathematicaStream &) const +{} + + +void InsetMathComment::octave(OctaveStream &) const +{} + + +void InsetMathComment::mathmlize(MathStream & os) const +{ + os << MTag("comment") << cell(0) << cell(1) << ETag("comment"); +} + + +void InsetMathComment::infoize(odocstream & os) const +{ + os << "Comment"; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathDFrac.C b/src/mathed/InsetMathDFrac.C deleted file mode 100644 index 5dded132b6..0000000000 --- a/src/mathed/InsetMathDFrac.C +++ /dev/null @@ -1,83 +0,0 @@ -/** - * \file InsetMathDFrac.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathDFrac.h" -#include "MathData.h" -#include "MathStream.h" -#include "LaTeXFeatures.h" -#include "LColor.h" -#include "frontends/Painter.h" - - -namespace lyx { - - -using std::string; -using std::max; -using std::auto_ptr; - - -InsetMathDFrac::InsetMathDFrac() - : InsetMathFrac() -{} - - -auto_ptr InsetMathDFrac::doClone() const -{ - return auto_ptr(new InsetMathDFrac(*this)); -} - - -bool InsetMathDFrac::metrics(MetricsInfo & mi, Dimension & dim) const -{ - cell(0).metrics(mi); - cell(1).metrics(mi); - dim.wid = max(cell(0).width(), cell(1).width()) + 2; - dim.asc = cell(0).height() + 2 + 5; - dim.des = cell(1).height() + 2 - 5; - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathDFrac::draw(PainterInfo & pi, int x, int y) const -{ - int m = x + dim_.wid / 2; - cell(0).draw(pi, m - cell(0).width() / 2, y - cell(0).descent() - 2 - 5); - cell(1).draw(pi, m - cell(1).width() / 2, y + cell(1).ascent() + 2 - 5); - pi.pain.line(x + 1, y - 5, x + dim_.wid - 2, y - 5, LColor::math); - setPosCache(pi, x, y); -} - - -docstring InsetMathDFrac::name() const -{ - return from_ascii("dfrac"); -} - - -void InsetMathDFrac::mathmlize(MathStream & os) const -{ - os << MTag("mdfrac") << cell(0) << cell(1) << ETag("mdfrac"); -} - - -void InsetMathDFrac::validate(LaTeXFeatures & features) const -{ - features.require("amsmath"); - InsetMathNest::validate(features); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathDFrac.cpp b/src/mathed/InsetMathDFrac.cpp new file mode 100644 index 0000000000..5dded132b6 --- /dev/null +++ b/src/mathed/InsetMathDFrac.cpp @@ -0,0 +1,83 @@ +/** + * \file InsetMathDFrac.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathDFrac.h" +#include "MathData.h" +#include "MathStream.h" +#include "LaTeXFeatures.h" +#include "LColor.h" +#include "frontends/Painter.h" + + +namespace lyx { + + +using std::string; +using std::max; +using std::auto_ptr; + + +InsetMathDFrac::InsetMathDFrac() + : InsetMathFrac() +{} + + +auto_ptr InsetMathDFrac::doClone() const +{ + return auto_ptr(new InsetMathDFrac(*this)); +} + + +bool InsetMathDFrac::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(0).metrics(mi); + cell(1).metrics(mi); + dim.wid = max(cell(0).width(), cell(1).width()) + 2; + dim.asc = cell(0).height() + 2 + 5; + dim.des = cell(1).height() + 2 - 5; + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathDFrac::draw(PainterInfo & pi, int x, int y) const +{ + int m = x + dim_.wid / 2; + cell(0).draw(pi, m - cell(0).width() / 2, y - cell(0).descent() - 2 - 5); + cell(1).draw(pi, m - cell(1).width() / 2, y + cell(1).ascent() + 2 - 5); + pi.pain.line(x + 1, y - 5, x + dim_.wid - 2, y - 5, LColor::math); + setPosCache(pi, x, y); +} + + +docstring InsetMathDFrac::name() const +{ + return from_ascii("dfrac"); +} + + +void InsetMathDFrac::mathmlize(MathStream & os) const +{ + os << MTag("mdfrac") << cell(0) << cell(1) << ETag("mdfrac"); +} + + +void InsetMathDFrac::validate(LaTeXFeatures & features) const +{ + features.require("amsmath"); + InsetMathNest::validate(features); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathDecoration.C b/src/mathed/InsetMathDecoration.C deleted file mode 100644 index f7a038bec8..0000000000 --- a/src/mathed/InsetMathDecoration.C +++ /dev/null @@ -1,168 +0,0 @@ -/** - * \file InsetMathDecoration.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Alejandro Aguilar Sierra - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathDecoration.h" -#include "MathData.h" -#include "MathParser.h" -#include "MathSupport.h" -#include "MathStream.h" - -#include "LaTeXFeatures.h" -#include "debug.h" - -#include "support/std_ostream.h" - - -namespace lyx { - - -InsetMathDecoration::InsetMathDecoration(latexkeys const * key) - : InsetMathNest(1), key_(key) -{ -// lyxerr << " creating deco " << key->name << std::endl; -} - - -std::auto_ptr InsetMathDecoration::doClone() const -{ - return std::auto_ptr(new InsetMathDecoration(*this)); -} - - -bool InsetMathDecoration::upper() const -{ - return key_->name.substr(0, 5) != "under"; -} - - -bool InsetMathDecoration::isScriptable() const -{ - return - key_->name == "overbrace" || - key_->name == "underbrace" || - key_->name == "overleftarrow" || - key_->name == "overrightarrow" || - key_->name == "overleftrightarrow" || - key_->name == "underleftarrow" || - key_->name == "underrightarrow" || - key_->name == "underleftrightarrow"; -} - - -bool InsetMathDecoration::protect() const -{ - return - key_->name == "overbrace" || - key_->name == "underbrace" || - key_->name == "overleftarrow" || - key_->name == "overrightarrow" || - key_->name == "overleftrightarrow" || - key_->name == "underleftarrow" || - key_->name == "underrightarrow" || - key_->name == "underleftrightarrow"; -} - - -bool InsetMathDecoration::wide() const -{ - return - key_->name == "overline" || - key_->name == "underline" || - key_->name == "overbrace" || - key_->name == "underbrace" || - key_->name == "overleftarrow" || - key_->name == "overrightarrow" || - key_->name == "overleftrightarrow" || - key_->name == "widehat" || - key_->name == "widetilde" || - key_->name == "underleftarrow" || - key_->name == "underrightarrow" || - key_->name == "underleftrightarrow"; -} - - -bool InsetMathDecoration::ams() const -{ - return - key_->name == "overleftrightarrow" || - key_->name == "underleftarrow" || - key_->name == "underrightarrow" || - key_->name == "underleftrightarrow"; -} - - -bool InsetMathDecoration::metrics(MetricsInfo & mi, Dimension & dim) const -{ - cell(0).metrics(mi, dim); - - dh_ = 6; //mathed_char_height(LM_TC_VAR, mi, 'I', ascent_, descent_); - dw_ = 6; //mathed_char_width(LM_TC_VAR, mi, 'x'); - - if (upper()) { - dy_ = -dim.asc - dh_; - dim.asc += dh_ + 1; - } else { - dy_ = dim.des + 1; - dim.des += dh_ + 2; - } - - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathDecoration::draw(PainterInfo & pi, int x, int y) const -{ - cell(0).draw(pi, x + 1, y); - if (wide()) - mathed_draw_deco(pi, x + 1, y + dy_, cell(0).width(), dh_, key_->name); - else - mathed_draw_deco(pi, x + 1 + (cell(0).width() - dw_) / 2, - y + dy_, dw_, dh_, key_->name); - drawMarkers(pi, x, y); - setPosCache(pi, x, y); -} - - -void InsetMathDecoration::write(WriteStream & os) const -{ - if (os.fragile() && protect()) - os << "\\protect"; - os << '\\' << key_->name << '{' << cell(0) << '}'; -} - - -void InsetMathDecoration::normalize(NormalStream & os) const -{ - os << "[deco " << key_->name << ' ' << cell(0) << ']'; -} - - -void InsetMathDecoration::infoize(odocstream & os) const -{ - os << "Deco: " << key_->name; -} - - -void InsetMathDecoration::validate(LaTeXFeatures & features) const -{ - if (ams()) - features.require("amsmath"); - InsetMathNest::validate(features); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathDecoration.cpp b/src/mathed/InsetMathDecoration.cpp new file mode 100644 index 0000000000..f7a038bec8 --- /dev/null +++ b/src/mathed/InsetMathDecoration.cpp @@ -0,0 +1,168 @@ +/** + * \file InsetMathDecoration.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Alejandro Aguilar Sierra + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathDecoration.h" +#include "MathData.h" +#include "MathParser.h" +#include "MathSupport.h" +#include "MathStream.h" + +#include "LaTeXFeatures.h" +#include "debug.h" + +#include "support/std_ostream.h" + + +namespace lyx { + + +InsetMathDecoration::InsetMathDecoration(latexkeys const * key) + : InsetMathNest(1), key_(key) +{ +// lyxerr << " creating deco " << key->name << std::endl; +} + + +std::auto_ptr InsetMathDecoration::doClone() const +{ + return std::auto_ptr(new InsetMathDecoration(*this)); +} + + +bool InsetMathDecoration::upper() const +{ + return key_->name.substr(0, 5) != "under"; +} + + +bool InsetMathDecoration::isScriptable() const +{ + return + key_->name == "overbrace" || + key_->name == "underbrace" || + key_->name == "overleftarrow" || + key_->name == "overrightarrow" || + key_->name == "overleftrightarrow" || + key_->name == "underleftarrow" || + key_->name == "underrightarrow" || + key_->name == "underleftrightarrow"; +} + + +bool InsetMathDecoration::protect() const +{ + return + key_->name == "overbrace" || + key_->name == "underbrace" || + key_->name == "overleftarrow" || + key_->name == "overrightarrow" || + key_->name == "overleftrightarrow" || + key_->name == "underleftarrow" || + key_->name == "underrightarrow" || + key_->name == "underleftrightarrow"; +} + + +bool InsetMathDecoration::wide() const +{ + return + key_->name == "overline" || + key_->name == "underline" || + key_->name == "overbrace" || + key_->name == "underbrace" || + key_->name == "overleftarrow" || + key_->name == "overrightarrow" || + key_->name == "overleftrightarrow" || + key_->name == "widehat" || + key_->name == "widetilde" || + key_->name == "underleftarrow" || + key_->name == "underrightarrow" || + key_->name == "underleftrightarrow"; +} + + +bool InsetMathDecoration::ams() const +{ + return + key_->name == "overleftrightarrow" || + key_->name == "underleftarrow" || + key_->name == "underrightarrow" || + key_->name == "underleftrightarrow"; +} + + +bool InsetMathDecoration::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(0).metrics(mi, dim); + + dh_ = 6; //mathed_char_height(LM_TC_VAR, mi, 'I', ascent_, descent_); + dw_ = 6; //mathed_char_width(LM_TC_VAR, mi, 'x'); + + if (upper()) { + dy_ = -dim.asc - dh_; + dim.asc += dh_ + 1; + } else { + dy_ = dim.des + 1; + dim.des += dh_ + 2; + } + + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathDecoration::draw(PainterInfo & pi, int x, int y) const +{ + cell(0).draw(pi, x + 1, y); + if (wide()) + mathed_draw_deco(pi, x + 1, y + dy_, cell(0).width(), dh_, key_->name); + else + mathed_draw_deco(pi, x + 1 + (cell(0).width() - dw_) / 2, + y + dy_, dw_, dh_, key_->name); + drawMarkers(pi, x, y); + setPosCache(pi, x, y); +} + + +void InsetMathDecoration::write(WriteStream & os) const +{ + if (os.fragile() && protect()) + os << "\\protect"; + os << '\\' << key_->name << '{' << cell(0) << '}'; +} + + +void InsetMathDecoration::normalize(NormalStream & os) const +{ + os << "[deco " << key_->name << ' ' << cell(0) << ']'; +} + + +void InsetMathDecoration::infoize(odocstream & os) const +{ + os << "Deco: " << key_->name; +} + + +void InsetMathDecoration::validate(LaTeXFeatures & features) const +{ + if (ams()) + features.require("amsmath"); + InsetMathNest::validate(features); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathDelim.C b/src/mathed/InsetMathDelim.C deleted file mode 100644 index a0f6aaad5d..0000000000 --- a/src/mathed/InsetMathDelim.C +++ /dev/null @@ -1,181 +0,0 @@ -/** - * \file InsetMathDelim.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Alejandro Aguilar Sierra - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathDelim.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathStream.h" -#include "MathSupport.h" - -#include "frontends/FontMetrics.h" - -namespace lyx { - - -using std::string; -using std::max; -using std::auto_ptr; - - -static docstring convertDelimToLatexName(docstring const & name) -{ - if (name.size() == 1) { - char_type const c = name[0]; - if (c == '<' || c == '(' || c == '[' || c == '.' - || c == '>' || c == ')' || c == ']' || c == '/' || c == '|') - return name; - } - return '\\' + name + ' '; -} - - -InsetMathDelim::InsetMathDelim(docstring const & l, docstring const & r) - : InsetMathNest(1), left_(l), right_(r) -{} - - -InsetMathDelim::InsetMathDelim - (docstring const & l, docstring const & r, MathArray const & ar) - : InsetMathNest(1), left_(l), right_(r) -{ - cell(0) = ar; -} - - -auto_ptr InsetMathDelim::doClone() const -{ - return auto_ptr(new InsetMathDelim(*this)); -} - - -void InsetMathDelim::write(WriteStream & os) const -{ - os << "\\left" << convertDelimToLatexName(left_) << cell(0) - << "\\right" << convertDelimToLatexName(right_); -} - - -void InsetMathDelim::normalize(NormalStream & os) const -{ - os << "[delim " << convertDelimToLatexName(left_) << ' ' - << convertDelimToLatexName(right_) << ' ' << cell(0) << ']'; -} - - -bool InsetMathDelim::metrics(MetricsInfo & mi, Dimension & dim) const -{ - cell(0).metrics(mi); - Dimension t = theFontMetrics(mi.base.font).dimension('I'); - int h0 = (t.asc + t.des) / 2; - int a0 = max(cell(0).ascent(), t.asc) - h0; - int d0 = max(cell(0).descent(), t.des) + h0; - dw_ = cell(0).height() / 5; - if (dw_ > 8) - dw_ = 8; - if (dw_ < 4) - dw_ = 4; - dim.wid = cell(0).width() + 2 * dw_ + 8; - dim.asc = max(a0, d0) + h0; - dim.des = max(a0, d0) - h0; - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathDelim::draw(PainterInfo & pi, int x, int y) const -{ - int const b = y - dim_.asc; - cell(0).draw(pi, x + dw_ + 4, y); - mathed_draw_deco(pi, x + 4, b, dw_, dim_.height(), left_); - mathed_draw_deco(pi, x + dim_.width() - dw_ - 4, - b, dw_, dim_.height(), right_); - setPosCache(pi, x, y); -} - - -bool InsetMathDelim::isParenthesis() const -{ - return left_ == "(" && right_ == ")"; -} - - -bool InsetMathDelim::isBrackets() const -{ - return left_ == "[" && right_ == "]"; -} - - -bool InsetMathDelim::isAbs() const -{ - return left_ == "|" && right_ == "|"; -} - - -void InsetMathDelim::maple(MapleStream & os) const -{ - if (isAbs()) { - if (cell(0).size() == 1 && cell(0).front()->asMatrixInset()) - os << "linalg[det](" << cell(0) << ')'; - else - os << "abs(" << cell(0) << ')'; - } - else - os << left_ << cell(0) << right_; -} - - -void InsetMathDelim::maxima(MaximaStream & os) const -{ - if (isAbs()) { - if (cell(0).size() == 1 && cell(0).front()->asMatrixInset()) - os << "determinant(" << cell(0) << ')'; - else - os << "abs(" << cell(0) << ')'; - } - else - os << left_ << cell(0) << right_; -} - - -void InsetMathDelim::mathematica(MathematicaStream & os) const -{ - if (isAbs()) { - if (cell(0).size() == 1 && cell(0).front()->asMatrixInset()) - os << "Det" << cell(0) << ']'; - else - os << "Abs[" << cell(0) << ']'; - } - else - os << left_ << cell(0) << right_; -} - - -void InsetMathDelim::mathmlize(MathStream & os) const -{ - os << "" << cell(0) << ""; -} - - -void InsetMathDelim::octave(OctaveStream & os) const -{ - if (isAbs()) - os << "det(" << cell(0) << ')'; - else - os << left_ << cell(0) << right_; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathDelim.cpp b/src/mathed/InsetMathDelim.cpp new file mode 100644 index 0000000000..a0f6aaad5d --- /dev/null +++ b/src/mathed/InsetMathDelim.cpp @@ -0,0 +1,181 @@ +/** + * \file InsetMathDelim.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Alejandro Aguilar Sierra + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathDelim.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathStream.h" +#include "MathSupport.h" + +#include "frontends/FontMetrics.h" + +namespace lyx { + + +using std::string; +using std::max; +using std::auto_ptr; + + +static docstring convertDelimToLatexName(docstring const & name) +{ + if (name.size() == 1) { + char_type const c = name[0]; + if (c == '<' || c == '(' || c == '[' || c == '.' + || c == '>' || c == ')' || c == ']' || c == '/' || c == '|') + return name; + } + return '\\' + name + ' '; +} + + +InsetMathDelim::InsetMathDelim(docstring const & l, docstring const & r) + : InsetMathNest(1), left_(l), right_(r) +{} + + +InsetMathDelim::InsetMathDelim + (docstring const & l, docstring const & r, MathArray const & ar) + : InsetMathNest(1), left_(l), right_(r) +{ + cell(0) = ar; +} + + +auto_ptr InsetMathDelim::doClone() const +{ + return auto_ptr(new InsetMathDelim(*this)); +} + + +void InsetMathDelim::write(WriteStream & os) const +{ + os << "\\left" << convertDelimToLatexName(left_) << cell(0) + << "\\right" << convertDelimToLatexName(right_); +} + + +void InsetMathDelim::normalize(NormalStream & os) const +{ + os << "[delim " << convertDelimToLatexName(left_) << ' ' + << convertDelimToLatexName(right_) << ' ' << cell(0) << ']'; +} + + +bool InsetMathDelim::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(0).metrics(mi); + Dimension t = theFontMetrics(mi.base.font).dimension('I'); + int h0 = (t.asc + t.des) / 2; + int a0 = max(cell(0).ascent(), t.asc) - h0; + int d0 = max(cell(0).descent(), t.des) + h0; + dw_ = cell(0).height() / 5; + if (dw_ > 8) + dw_ = 8; + if (dw_ < 4) + dw_ = 4; + dim.wid = cell(0).width() + 2 * dw_ + 8; + dim.asc = max(a0, d0) + h0; + dim.des = max(a0, d0) - h0; + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathDelim::draw(PainterInfo & pi, int x, int y) const +{ + int const b = y - dim_.asc; + cell(0).draw(pi, x + dw_ + 4, y); + mathed_draw_deco(pi, x + 4, b, dw_, dim_.height(), left_); + mathed_draw_deco(pi, x + dim_.width() - dw_ - 4, + b, dw_, dim_.height(), right_); + setPosCache(pi, x, y); +} + + +bool InsetMathDelim::isParenthesis() const +{ + return left_ == "(" && right_ == ")"; +} + + +bool InsetMathDelim::isBrackets() const +{ + return left_ == "[" && right_ == "]"; +} + + +bool InsetMathDelim::isAbs() const +{ + return left_ == "|" && right_ == "|"; +} + + +void InsetMathDelim::maple(MapleStream & os) const +{ + if (isAbs()) { + if (cell(0).size() == 1 && cell(0).front()->asMatrixInset()) + os << "linalg[det](" << cell(0) << ')'; + else + os << "abs(" << cell(0) << ')'; + } + else + os << left_ << cell(0) << right_; +} + + +void InsetMathDelim::maxima(MaximaStream & os) const +{ + if (isAbs()) { + if (cell(0).size() == 1 && cell(0).front()->asMatrixInset()) + os << "determinant(" << cell(0) << ')'; + else + os << "abs(" << cell(0) << ')'; + } + else + os << left_ << cell(0) << right_; +} + + +void InsetMathDelim::mathematica(MathematicaStream & os) const +{ + if (isAbs()) { + if (cell(0).size() == 1 && cell(0).front()->asMatrixInset()) + os << "Det" << cell(0) << ']'; + else + os << "Abs[" << cell(0) << ']'; + } + else + os << left_ << cell(0) << right_; +} + + +void InsetMathDelim::mathmlize(MathStream & os) const +{ + os << "" << cell(0) << ""; +} + + +void InsetMathDelim::octave(OctaveStream & os) const +{ + if (isAbs()) + os << "det(" << cell(0) << ')'; + else + os << left_ << cell(0) << right_; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathDiff.C b/src/mathed/InsetMathDiff.C deleted file mode 100644 index 2f866d245b..0000000000 --- a/src/mathed/InsetMathDiff.C +++ /dev/null @@ -1,120 +0,0 @@ -/** - * \file InsetMathDiff.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathDiff.h" -#include "MathData.h" -#include "MathStream.h" -#include "debug.h" - - -namespace lyx { - -using std::auto_ptr; -using std::endl; - - -InsetMathDiff::InsetMathDiff() - : InsetMathNest(1) -{} - - -auto_ptr InsetMathDiff::doClone() const -{ - return auto_ptr(new InsetMathDiff(*this)); -} - - -void InsetMathDiff::addDer(MathArray const & der) -{ - cells_.push_back(der); -} - - -void InsetMathDiff::normalize(NormalStream & os) const -{ - os << "[diff"; - for (idx_type idx = 0; idx < nargs(); ++idx) - os << ' ' << cell(idx); - os << ']'; -} - - -bool InsetMathDiff::metrics(MetricsInfo &, Dimension &) const -{ - lyxerr << "should not happen" << endl; - return true; -} - - -void InsetMathDiff::draw(PainterInfo &, int, int) const -{ - lyxerr << "should not happen" << endl; -} - - -void InsetMathDiff::maple(MapleStream & os) const -{ - os << "diff("; - for (idx_type idx = 0; idx < nargs(); ++idx) { - if (idx != 0) - os << ','; - os << cell(idx); - } - os << ')'; -} - - -void InsetMathDiff::maxima(MaximaStream & os) const -{ - os << "diff("; - for (idx_type idx = 0; idx < nargs(); ++idx) { - if (idx != 0) - os << ','; - os << cell(idx); - if (idx != 0) - os << ",1"; - } - os << ')'; -} - - -void InsetMathDiff::mathematica(MathematicaStream & os) const -{ - os << "D["; - for (idx_type idx = 0; idx < nargs(); ++idx) { - if (idx != 0) - os << ','; - os << cell(idx); - } - os << ']'; -} - - -void InsetMathDiff::mathmlize(MathStream & os) const -{ - os << "diff("; - for (idx_type idx = 0; idx < nargs(); ++idx) { - if (idx != 0) - os << ','; - os << cell(idx); - } - os << ')'; -} - - -void InsetMathDiff::write(WriteStream &) const -{ - lyxerr << "should not happen" << endl; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathDiff.cpp b/src/mathed/InsetMathDiff.cpp new file mode 100644 index 0000000000..2f866d245b --- /dev/null +++ b/src/mathed/InsetMathDiff.cpp @@ -0,0 +1,120 @@ +/** + * \file InsetMathDiff.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathDiff.h" +#include "MathData.h" +#include "MathStream.h" +#include "debug.h" + + +namespace lyx { + +using std::auto_ptr; +using std::endl; + + +InsetMathDiff::InsetMathDiff() + : InsetMathNest(1) +{} + + +auto_ptr InsetMathDiff::doClone() const +{ + return auto_ptr(new InsetMathDiff(*this)); +} + + +void InsetMathDiff::addDer(MathArray const & der) +{ + cells_.push_back(der); +} + + +void InsetMathDiff::normalize(NormalStream & os) const +{ + os << "[diff"; + for (idx_type idx = 0; idx < nargs(); ++idx) + os << ' ' << cell(idx); + os << ']'; +} + + +bool InsetMathDiff::metrics(MetricsInfo &, Dimension &) const +{ + lyxerr << "should not happen" << endl; + return true; +} + + +void InsetMathDiff::draw(PainterInfo &, int, int) const +{ + lyxerr << "should not happen" << endl; +} + + +void InsetMathDiff::maple(MapleStream & os) const +{ + os << "diff("; + for (idx_type idx = 0; idx < nargs(); ++idx) { + if (idx != 0) + os << ','; + os << cell(idx); + } + os << ')'; +} + + +void InsetMathDiff::maxima(MaximaStream & os) const +{ + os << "diff("; + for (idx_type idx = 0; idx < nargs(); ++idx) { + if (idx != 0) + os << ','; + os << cell(idx); + if (idx != 0) + os << ",1"; + } + os << ')'; +} + + +void InsetMathDiff::mathematica(MathematicaStream & os) const +{ + os << "D["; + for (idx_type idx = 0; idx < nargs(); ++idx) { + if (idx != 0) + os << ','; + os << cell(idx); + } + os << ']'; +} + + +void InsetMathDiff::mathmlize(MathStream & os) const +{ + os << "diff("; + for (idx_type idx = 0; idx < nargs(); ++idx) { + if (idx != 0) + os << ','; + os << cell(idx); + } + os << ')'; +} + + +void InsetMathDiff::write(WriteStream &) const +{ + lyxerr << "should not happen" << endl; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathDim.C b/src/mathed/InsetMathDim.C deleted file mode 100644 index e74bbbc2c6..0000000000 --- a/src/mathed/InsetMathDim.C +++ /dev/null @@ -1,35 +0,0 @@ -/** - * \file InsetMathDim.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathDim.h" - -#include "BufferView.h" -#include "coordcache.h" -#include "debug.h" -#include "metricsinfo.h" - - -namespace lyx { - - -InsetMathDim::InsetMathDim() -{} - - -void InsetMathDim::setPosCache(PainterInfo const & pi, int x, int y) const -{ - //lyxerr << "InsetMathDim: cache to " << x << " " << y << std::endl; - pi.base.bv->coordCache().insets().add(this, x, y); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathDim.cpp b/src/mathed/InsetMathDim.cpp new file mode 100644 index 0000000000..e74bbbc2c6 --- /dev/null +++ b/src/mathed/InsetMathDim.cpp @@ -0,0 +1,35 @@ +/** + * \file InsetMathDim.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathDim.h" + +#include "BufferView.h" +#include "coordcache.h" +#include "debug.h" +#include "metricsinfo.h" + + +namespace lyx { + + +InsetMathDim::InsetMathDim() +{} + + +void InsetMathDim::setPosCache(PainterInfo const & pi, int x, int y) const +{ + //lyxerr << "InsetMathDim: cache to " << x << " " << y << std::endl; + pi.base.bv->coordCache().insets().add(this, x, y); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathDots.C b/src/mathed/InsetMathDots.C deleted file mode 100644 index 6673d04838..0000000000 --- a/src/mathed/InsetMathDots.C +++ /dev/null @@ -1,81 +0,0 @@ -/** - * \file InsetMathDots.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Alejandro Aguilar Sierra - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathDots.h" -#include "MathStream.h" -#include "MathSupport.h" -#include "MathParser.h" - -#include "frontends/FontMetrics.h" - -namespace lyx { - - -using std::string; -using std::auto_ptr; - - -InsetMathDots::InsetMathDots(latexkeys const * key) - : key_(key) -{} - - -auto_ptr InsetMathDots::doClone() const -{ - return auto_ptr(new InsetMathDots(*this)); -} - - -bool InsetMathDots::metrics(MetricsInfo & mi, Dimension & dim) const -{ - dim = theFontMetrics(mi.base.font).dimension('M'); - dh_ = 0; - if (key_->name == "cdots" || key_->name == "dotsb" - || key_->name == "dotsm" || key_->name == "dotsi") - dh_ = dim.asc / 2; - else if (key_->name == "dotsc") - dh_ = dim.asc / 4; - else if (key_->name == "vdots") { - dim.wid = (dim.wid / 2) + 1; - dh_ = dim.asc; - } - else if (key_->name == "ddots") - dh_ = dim.asc; - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathDots::draw(PainterInfo & pain, int x, int y) const -{ - mathed_draw_deco(pain, x + 2, y - dh_, dim_.width() - 2, dim_.ascent(), - key_->name); - if (key_->name == "vdots" || key_->name == "ddots") - ++x; - if (key_->name != "vdots") - --y; - mathed_draw_deco(pain, x + 2, y - dh_, dim_.width() - 2, dim_.ascent(), - key_->name); - setPosCache(pain, x, y); -} - - -docstring InsetMathDots::name() const -{ - return key_->name; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathDots.cpp b/src/mathed/InsetMathDots.cpp new file mode 100644 index 0000000000..6673d04838 --- /dev/null +++ b/src/mathed/InsetMathDots.cpp @@ -0,0 +1,81 @@ +/** + * \file InsetMathDots.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Alejandro Aguilar Sierra + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathDots.h" +#include "MathStream.h" +#include "MathSupport.h" +#include "MathParser.h" + +#include "frontends/FontMetrics.h" + +namespace lyx { + + +using std::string; +using std::auto_ptr; + + +InsetMathDots::InsetMathDots(latexkeys const * key) + : key_(key) +{} + + +auto_ptr InsetMathDots::doClone() const +{ + return auto_ptr(new InsetMathDots(*this)); +} + + +bool InsetMathDots::metrics(MetricsInfo & mi, Dimension & dim) const +{ + dim = theFontMetrics(mi.base.font).dimension('M'); + dh_ = 0; + if (key_->name == "cdots" || key_->name == "dotsb" + || key_->name == "dotsm" || key_->name == "dotsi") + dh_ = dim.asc / 2; + else if (key_->name == "dotsc") + dh_ = dim.asc / 4; + else if (key_->name == "vdots") { + dim.wid = (dim.wid / 2) + 1; + dh_ = dim.asc; + } + else if (key_->name == "ddots") + dh_ = dim.asc; + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathDots::draw(PainterInfo & pain, int x, int y) const +{ + mathed_draw_deco(pain, x + 2, y - dh_, dim_.width() - 2, dim_.ascent(), + key_->name); + if (key_->name == "vdots" || key_->name == "ddots") + ++x; + if (key_->name != "vdots") + --y; + mathed_draw_deco(pain, x + 2, y - dh_, dim_.width() - 2, dim_.ascent(), + key_->name); + setPosCache(pain, x, y); +} + + +docstring InsetMathDots::name() const +{ + return key_->name; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathEnv.C b/src/mathed/InsetMathEnv.C deleted file mode 100644 index 110d09b259..0000000000 --- a/src/mathed/InsetMathEnv.C +++ /dev/null @@ -1,74 +0,0 @@ -/** - * \file InsetMathEnv.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathEnv.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathStream.h" -#include "support/std_ostream.h" - - -namespace lyx { - - -using std::string; -using std::auto_ptr; - - -InsetMathEnv::InsetMathEnv(docstring const & name) - : InsetMathNest(1), name_(name) -{} - - -auto_ptr InsetMathEnv::doClone() const -{ - return auto_ptr(new InsetMathEnv(*this)); -} - - -bool InsetMathEnv::metrics(MetricsInfo & mi, Dimension & dim) const -{ - cell(0).metrics(mi, dim); - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathEnv::draw(PainterInfo & pi, int x, int y) const -{ - cell(0).draw(pi, x + 1, y); - drawMarkers(pi, x, y); -} - - -void InsetMathEnv::write(WriteStream & os) const -{ - os << "\\begin{" << name_ << '}' << cell(0) << "\\end{" << name_ << '}'; -} - - -void InsetMathEnv::normalize(NormalStream & os) const -{ - os << "[env " << name_ << ' ' << cell(0) << ']'; -} - - -void InsetMathEnv::infoize(odocstream & os) const -{ - os << "Env: " << name_; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathEnv.cpp b/src/mathed/InsetMathEnv.cpp new file mode 100644 index 0000000000..110d09b259 --- /dev/null +++ b/src/mathed/InsetMathEnv.cpp @@ -0,0 +1,74 @@ +/** + * \file InsetMathEnv.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathEnv.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathStream.h" +#include "support/std_ostream.h" + + +namespace lyx { + + +using std::string; +using std::auto_ptr; + + +InsetMathEnv::InsetMathEnv(docstring const & name) + : InsetMathNest(1), name_(name) +{} + + +auto_ptr InsetMathEnv::doClone() const +{ + return auto_ptr(new InsetMathEnv(*this)); +} + + +bool InsetMathEnv::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(0).metrics(mi, dim); + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathEnv::draw(PainterInfo & pi, int x, int y) const +{ + cell(0).draw(pi, x + 1, y); + drawMarkers(pi, x, y); +} + + +void InsetMathEnv::write(WriteStream & os) const +{ + os << "\\begin{" << name_ << '}' << cell(0) << "\\end{" << name_ << '}'; +} + + +void InsetMathEnv::normalize(NormalStream & os) const +{ + os << "[env " << name_ << ' ' << cell(0) << ']'; +} + + +void InsetMathEnv::infoize(odocstream & os) const +{ + os << "Env: " << name_; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathExFunc.C b/src/mathed/InsetMathExFunc.C deleted file mode 100644 index 9ede0e4340..0000000000 --- a/src/mathed/InsetMathExFunc.C +++ /dev/null @@ -1,141 +0,0 @@ -/** - * \file InsetMathExFunc.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathExFunc.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathStream.h" -#include "MathSupport.h" - - -namespace lyx { - -using std::auto_ptr; -using std::vector; -using std::string; - - -InsetMathExFunc::InsetMathExFunc(docstring const & name) - : InsetMathNest(1), name_(name) -{} - - -InsetMathExFunc::InsetMathExFunc(docstring const & name, MathArray const & ar) - : InsetMathNest(1), name_(name) -{ - cell(0) = ar; -} - - -auto_ptr InsetMathExFunc::doClone() const -{ - return auto_ptr(new InsetMathExFunc(*this)); -} - - -bool InsetMathExFunc::metrics(MetricsInfo & mi, Dimension & dim) const -{ - mathed_string_dim(mi.base.font, name_, dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathExFunc::draw(PainterInfo & pi, int x, int y) const -{ - drawStrBlack(pi, x, y, name_); -} - - -docstring InsetMathExFunc::name() const -{ - return name_; -} - - -void InsetMathExFunc::maple(MapleStream & os) const -{ - if (name_ == "det") - os << "linalg[det](" << cell(0) << ')'; - else - os << name_ << '(' << cell(0) << ')'; -} - - -void InsetMathExFunc::maxima(MaximaStream & os) const -{ - if (name_ == "det") - os << "determinant(" << cell(0) << ')'; - else - os << name_ << '(' << cell(0) << ')'; -} - - -static string asMathematicaName(string const & name) -{ - if (name == "sin") return "Sin"; - if (name == "sinh") return "Sinh"; - if (name == "arcsin") return "ArcSin"; - if (name == "asin") return "ArcSin"; - if (name == "cos") return "Cos"; - if (name == "cosh") return "Cosh"; - if (name == "arccos") return "ArcCos"; - if (name == "acos") return "ArcCos"; - if (name == "tan") return "Tan"; - if (name == "tanh") return "Tanh"; - if (name == "arctan") return "ArcTan"; - if (name == "atan") return "ArcTan"; - if (name == "cot") return "Cot"; - if (name == "coth") return "Coth"; - if (name == "csc") return "Csc"; - if (name == "sec") return "Sec"; - if (name == "exp") return "Exp"; - if (name == "log") return "Log"; - if (name == "ln" ) return "Log"; - if (name == "arg" ) return "Arg"; - if (name == "det" ) return "Det"; - if (name == "gcd" ) return "GCD"; - if (name == "max" ) return "Max"; - if (name == "min" ) return "Min"; - if (name == "erf" ) return "Erf"; - if (name == "erfc" ) return "Erfc"; - return name; -} - - -static docstring asMathematicaName(docstring const & name) -{ - return from_utf8(asMathematicaName(to_utf8(name))); -} - - -void InsetMathExFunc::mathematica(MathematicaStream & os) const -{ - os << asMathematicaName(name_) << '[' << cell(0) << ']'; -} - - -void InsetMathExFunc::mathmlize(MathStream & os) const -{ - os << MTag(name_.c_str()) << cell(0) << ETag(name_.c_str()); -} - - -void InsetMathExFunc::octave(OctaveStream & os) const -{ - os << name_ << '(' << cell(0) << ')'; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathExFunc.cpp b/src/mathed/InsetMathExFunc.cpp new file mode 100644 index 0000000000..9ede0e4340 --- /dev/null +++ b/src/mathed/InsetMathExFunc.cpp @@ -0,0 +1,141 @@ +/** + * \file InsetMathExFunc.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathExFunc.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathStream.h" +#include "MathSupport.h" + + +namespace lyx { + +using std::auto_ptr; +using std::vector; +using std::string; + + +InsetMathExFunc::InsetMathExFunc(docstring const & name) + : InsetMathNest(1), name_(name) +{} + + +InsetMathExFunc::InsetMathExFunc(docstring const & name, MathArray const & ar) + : InsetMathNest(1), name_(name) +{ + cell(0) = ar; +} + + +auto_ptr InsetMathExFunc::doClone() const +{ + return auto_ptr(new InsetMathExFunc(*this)); +} + + +bool InsetMathExFunc::metrics(MetricsInfo & mi, Dimension & dim) const +{ + mathed_string_dim(mi.base.font, name_, dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathExFunc::draw(PainterInfo & pi, int x, int y) const +{ + drawStrBlack(pi, x, y, name_); +} + + +docstring InsetMathExFunc::name() const +{ + return name_; +} + + +void InsetMathExFunc::maple(MapleStream & os) const +{ + if (name_ == "det") + os << "linalg[det](" << cell(0) << ')'; + else + os << name_ << '(' << cell(0) << ')'; +} + + +void InsetMathExFunc::maxima(MaximaStream & os) const +{ + if (name_ == "det") + os << "determinant(" << cell(0) << ')'; + else + os << name_ << '(' << cell(0) << ')'; +} + + +static string asMathematicaName(string const & name) +{ + if (name == "sin") return "Sin"; + if (name == "sinh") return "Sinh"; + if (name == "arcsin") return "ArcSin"; + if (name == "asin") return "ArcSin"; + if (name == "cos") return "Cos"; + if (name == "cosh") return "Cosh"; + if (name == "arccos") return "ArcCos"; + if (name == "acos") return "ArcCos"; + if (name == "tan") return "Tan"; + if (name == "tanh") return "Tanh"; + if (name == "arctan") return "ArcTan"; + if (name == "atan") return "ArcTan"; + if (name == "cot") return "Cot"; + if (name == "coth") return "Coth"; + if (name == "csc") return "Csc"; + if (name == "sec") return "Sec"; + if (name == "exp") return "Exp"; + if (name == "log") return "Log"; + if (name == "ln" ) return "Log"; + if (name == "arg" ) return "Arg"; + if (name == "det" ) return "Det"; + if (name == "gcd" ) return "GCD"; + if (name == "max" ) return "Max"; + if (name == "min" ) return "Min"; + if (name == "erf" ) return "Erf"; + if (name == "erfc" ) return "Erfc"; + return name; +} + + +static docstring asMathematicaName(docstring const & name) +{ + return from_utf8(asMathematicaName(to_utf8(name))); +} + + +void InsetMathExFunc::mathematica(MathematicaStream & os) const +{ + os << asMathematicaName(name_) << '[' << cell(0) << ']'; +} + + +void InsetMathExFunc::mathmlize(MathStream & os) const +{ + os << MTag(name_.c_str()) << cell(0) << ETag(name_.c_str()); +} + + +void InsetMathExFunc::octave(OctaveStream & os) const +{ + os << name_ << '(' << cell(0) << ')'; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathExInt.C b/src/mathed/InsetMathExInt.C deleted file mode 100644 index 23fca486bc..0000000000 --- a/src/mathed/InsetMathExInt.C +++ /dev/null @@ -1,151 +0,0 @@ -/** - * \file InsetMathExInt.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathExInt.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathStream.h" -#include "InsetMathSymbol.h" -#include "debug.h" - -#include - - -namespace lyx { - - -using std::string; -using std::auto_ptr; -using std::endl; - - -InsetMathExInt::InsetMathExInt(docstring const & name) - : InsetMathNest(4), symbol_(name) -{} - -// 0 - core -// 1 - diff -// 2 - lower -// 3 - upper - - -auto_ptr InsetMathExInt::doClone() const -{ - return auto_ptr(new InsetMathExInt(*this)); -} - - -void InsetMathExInt::symbol(docstring const & symbol) -{ - symbol_ = symbol; -} - - -bool InsetMathExInt::hasScripts() const -{ - // take empty upper bound as "no scripts" - return !cell(3).empty(); -} - - - -void InsetMathExInt::normalize(NormalStream & os) const -{ - os << '[' << symbol_ << ' ' << cell(0) << ' ' << cell(1) << ' ' - << cell(2) << ' ' << cell(3) << ']'; -} - - -bool InsetMathExInt::metrics(MetricsInfo &, Dimension &) const -{ - lyxerr << "should not happen" << endl; - return true; -} - - -void InsetMathExInt::draw(PainterInfo &, int, int) const -{ - lyxerr << "should not happen" << endl; -} - - -void InsetMathExInt::maple(MapleStream & os) const -{ - os << symbol_ << '('; - if (cell(0).size()) - os << cell(0); - else - os << '1'; - os << ',' << cell(1); - if (hasScripts()) - os << '=' << cell(2) << ".." << cell(3); - os << ')'; -} - - -void InsetMathExInt::maxima(MaximaStream & os) const -{ - if ( symbol_ == "int" ) - os << "integrate("; - else - os << symbol_ << '('; - - if (cell(0).size()) - os << cell(0) << ','; - else - os << '1' << ','; - if (hasScripts()) - os << cell(1) << ',' << cell(2) << ',' << cell(3) << ')'; - else - os << cell(1) << ')'; -} - -void InsetMathExInt::mathematica(MathematicaStream & os) const -{ - if ( symbol_ == "int" ) - os << "Integrate["; - else if (symbol_ == "sum") - os << "Sum["; - else - os << symbol_ << '['; - - if (cell(0).size()) - os << cell(0) << ','; - else - os << '1' << ','; - if (hasScripts()) - os << '{' << cell(1) << ',' << cell(2) << ',' << cell(3) << "}]"; - else - os << cell(1) << ']'; -} - - -void InsetMathExInt::mathmlize(MathStream & os) const -{ - boost::scoped_ptr sym(new InsetMathSymbol(symbol_)); - //if (hasScripts()) - // mathmlize(sym, os); - //else - sym->mathmlize(os); - os << cell(0) << "" - << MTag("mrow") << "" - << cell(1) << ETag("mrow"); -} - - -void InsetMathExInt::write(WriteStream &) const -{ - lyxerr << "should not happen" << endl; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathExInt.cpp b/src/mathed/InsetMathExInt.cpp new file mode 100644 index 0000000000..23fca486bc --- /dev/null +++ b/src/mathed/InsetMathExInt.cpp @@ -0,0 +1,151 @@ +/** + * \file InsetMathExInt.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathExInt.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathStream.h" +#include "InsetMathSymbol.h" +#include "debug.h" + +#include + + +namespace lyx { + + +using std::string; +using std::auto_ptr; +using std::endl; + + +InsetMathExInt::InsetMathExInt(docstring const & name) + : InsetMathNest(4), symbol_(name) +{} + +// 0 - core +// 1 - diff +// 2 - lower +// 3 - upper + + +auto_ptr InsetMathExInt::doClone() const +{ + return auto_ptr(new InsetMathExInt(*this)); +} + + +void InsetMathExInt::symbol(docstring const & symbol) +{ + symbol_ = symbol; +} + + +bool InsetMathExInt::hasScripts() const +{ + // take empty upper bound as "no scripts" + return !cell(3).empty(); +} + + + +void InsetMathExInt::normalize(NormalStream & os) const +{ + os << '[' << symbol_ << ' ' << cell(0) << ' ' << cell(1) << ' ' + << cell(2) << ' ' << cell(3) << ']'; +} + + +bool InsetMathExInt::metrics(MetricsInfo &, Dimension &) const +{ + lyxerr << "should not happen" << endl; + return true; +} + + +void InsetMathExInt::draw(PainterInfo &, int, int) const +{ + lyxerr << "should not happen" << endl; +} + + +void InsetMathExInt::maple(MapleStream & os) const +{ + os << symbol_ << '('; + if (cell(0).size()) + os << cell(0); + else + os << '1'; + os << ',' << cell(1); + if (hasScripts()) + os << '=' << cell(2) << ".." << cell(3); + os << ')'; +} + + +void InsetMathExInt::maxima(MaximaStream & os) const +{ + if ( symbol_ == "int" ) + os << "integrate("; + else + os << symbol_ << '('; + + if (cell(0).size()) + os << cell(0) << ','; + else + os << '1' << ','; + if (hasScripts()) + os << cell(1) << ',' << cell(2) << ',' << cell(3) << ')'; + else + os << cell(1) << ')'; +} + +void InsetMathExInt::mathematica(MathematicaStream & os) const +{ + if ( symbol_ == "int" ) + os << "Integrate["; + else if (symbol_ == "sum") + os << "Sum["; + else + os << symbol_ << '['; + + if (cell(0).size()) + os << cell(0) << ','; + else + os << '1' << ','; + if (hasScripts()) + os << '{' << cell(1) << ',' << cell(2) << ',' << cell(3) << "}]"; + else + os << cell(1) << ']'; +} + + +void InsetMathExInt::mathmlize(MathStream & os) const +{ + boost::scoped_ptr sym(new InsetMathSymbol(symbol_)); + //if (hasScripts()) + // mathmlize(sym, os); + //else + sym->mathmlize(os); + os << cell(0) << "" + << MTag("mrow") << "" + << cell(1) << ETag("mrow"); +} + + +void InsetMathExInt::write(WriteStream &) const +{ + lyxerr << "should not happen" << endl; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathFBox.C b/src/mathed/InsetMathFBox.C deleted file mode 100644 index 4eb91a8b97..0000000000 --- a/src/mathed/InsetMathFBox.C +++ /dev/null @@ -1,84 +0,0 @@ -/** - * \file InsetMathFBox.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathFBox.h" -#include "MathData.h" -#include "MathStream.h" -#include "LColor.h" - -#include "support/std_ostream.h" -#include "frontends/Painter.h" - - -namespace lyx { - -using std::auto_ptr; - - -InsetMathFBox::InsetMathFBox() - : InsetMathNest(1) -{} - - -auto_ptr InsetMathFBox::doClone() const -{ - return auto_ptr(new InsetMathFBox(*this)); -} - - -InsetMath::mode_type InsetMathFBox::currentMode() const -{ - return TEXT_MODE; -} - - -bool InsetMathFBox::metrics(MetricsInfo & mi, Dimension & dim) const -{ - FontSetChanger dummy(mi.base, "textnormal"); - cell(0).metrics(mi, dim); - metricsMarkers(dim, 3); // 1 pixel space, 1 frame, 1 space - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathFBox::draw(PainterInfo & pi, int x, int y) const -{ - pi.pain.rectangle(x + 1, y - dim_.ascent() + 1, - dim_.width() - 2, dim_.height() - 2, LColor::foreground); - FontSetChanger dummy(pi.base, "textnormal"); - cell(0).draw(pi, x + 3, y); - setPosCache(pi, x, y); -} - - -void InsetMathFBox::write(WriteStream & os) const -{ - os << "\\fbox{" << cell(0) << '}'; -} - - -void InsetMathFBox::normalize(NormalStream & os) const -{ - os << "[fbox " << cell(0) << ']'; -} - - -void InsetMathFBox::infoize(odocstream & os) const -{ - os << "FBox: "; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathFBox.cpp b/src/mathed/InsetMathFBox.cpp new file mode 100644 index 0000000000..4eb91a8b97 --- /dev/null +++ b/src/mathed/InsetMathFBox.cpp @@ -0,0 +1,84 @@ +/** + * \file InsetMathFBox.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathFBox.h" +#include "MathData.h" +#include "MathStream.h" +#include "LColor.h" + +#include "support/std_ostream.h" +#include "frontends/Painter.h" + + +namespace lyx { + +using std::auto_ptr; + + +InsetMathFBox::InsetMathFBox() + : InsetMathNest(1) +{} + + +auto_ptr InsetMathFBox::doClone() const +{ + return auto_ptr(new InsetMathFBox(*this)); +} + + +InsetMath::mode_type InsetMathFBox::currentMode() const +{ + return TEXT_MODE; +} + + +bool InsetMathFBox::metrics(MetricsInfo & mi, Dimension & dim) const +{ + FontSetChanger dummy(mi.base, "textnormal"); + cell(0).metrics(mi, dim); + metricsMarkers(dim, 3); // 1 pixel space, 1 frame, 1 space + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathFBox::draw(PainterInfo & pi, int x, int y) const +{ + pi.pain.rectangle(x + 1, y - dim_.ascent() + 1, + dim_.width() - 2, dim_.height() - 2, LColor::foreground); + FontSetChanger dummy(pi.base, "textnormal"); + cell(0).draw(pi, x + 3, y); + setPosCache(pi, x, y); +} + + +void InsetMathFBox::write(WriteStream & os) const +{ + os << "\\fbox{" << cell(0) << '}'; +} + + +void InsetMathFBox::normalize(NormalStream & os) const +{ + os << "[fbox " << cell(0) << ']'; +} + + +void InsetMathFBox::infoize(odocstream & os) const +{ + os << "FBox: "; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathFont.C b/src/mathed/InsetMathFont.C deleted file mode 100644 index e079868a1a..0000000000 --- a/src/mathed/InsetMathFont.C +++ /dev/null @@ -1,106 +0,0 @@ -/** - * \file InsetMathFont.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathFont.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathParser.h" -#include "LaTeXFeatures.h" -#include "support/std_ostream.h" - - -namespace lyx { - -using std::auto_ptr; - - -InsetMathFont::InsetMathFont(latexkeys const * key) - : InsetMathNest(1), key_(key) -{} - - -auto_ptr InsetMathFont::doClone() const -{ - return auto_ptr(new InsetMathFont(*this)); -} - - -InsetMath::mode_type InsetMathFont::currentMode() const -{ - if (key_->extra == "mathmode") - return MATH_MODE; - if (key_->extra == "textmode") - return TEXT_MODE; - return UNDECIDED_MODE; -} - - -bool InsetMathFont::metrics(MetricsInfo & mi, Dimension & dim) const -{ - FontSetChanger dummy(mi.base, key_->name); - cell(0).metrics(mi, dim); - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathFont::draw(PainterInfo & pi, int x, int y) const -{ - FontSetChanger dummy(pi.base, key_->name.c_str()); - cell(0).draw(pi, x + 1, y); - drawMarkers(pi, x, y); - setPosCache(pi, x, y); -} - - -void InsetMathFont::metricsT(TextMetricsInfo const & mi, Dimension &) const -{ - cell(0).metricsT(mi, dim_); -} - - -void InsetMathFont::drawT(TextPainter & pain, int x, int y) const -{ - cell(0).drawT(pain, x, y); -} - - -docstring InsetMathFont::name() const -{ - return key_->name; -} - - -void InsetMathFont::validate(LaTeXFeatures & features) const -{ - InsetMathNest::validate(features); - // Make sure amssymb is put in preamble if Blackboard Bold or - // Fraktur used: - if (key_->name == "mathfrak" || key_->name == "mathbb") - features.require("amssymb"); - if (key_->name == "text") - features.require("amsmath"); - if (key_->name == "textipa") - features.require("tipa"); -} - - -void InsetMathFont::infoize(odocstream & os) const -{ - os << "Font: " << key_->name; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathFont.cpp b/src/mathed/InsetMathFont.cpp new file mode 100644 index 0000000000..e079868a1a --- /dev/null +++ b/src/mathed/InsetMathFont.cpp @@ -0,0 +1,106 @@ +/** + * \file InsetMathFont.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathFont.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathParser.h" +#include "LaTeXFeatures.h" +#include "support/std_ostream.h" + + +namespace lyx { + +using std::auto_ptr; + + +InsetMathFont::InsetMathFont(latexkeys const * key) + : InsetMathNest(1), key_(key) +{} + + +auto_ptr InsetMathFont::doClone() const +{ + return auto_ptr(new InsetMathFont(*this)); +} + + +InsetMath::mode_type InsetMathFont::currentMode() const +{ + if (key_->extra == "mathmode") + return MATH_MODE; + if (key_->extra == "textmode") + return TEXT_MODE; + return UNDECIDED_MODE; +} + + +bool InsetMathFont::metrics(MetricsInfo & mi, Dimension & dim) const +{ + FontSetChanger dummy(mi.base, key_->name); + cell(0).metrics(mi, dim); + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathFont::draw(PainterInfo & pi, int x, int y) const +{ + FontSetChanger dummy(pi.base, key_->name.c_str()); + cell(0).draw(pi, x + 1, y); + drawMarkers(pi, x, y); + setPosCache(pi, x, y); +} + + +void InsetMathFont::metricsT(TextMetricsInfo const & mi, Dimension &) const +{ + cell(0).metricsT(mi, dim_); +} + + +void InsetMathFont::drawT(TextPainter & pain, int x, int y) const +{ + cell(0).drawT(pain, x, y); +} + + +docstring InsetMathFont::name() const +{ + return key_->name; +} + + +void InsetMathFont::validate(LaTeXFeatures & features) const +{ + InsetMathNest::validate(features); + // Make sure amssymb is put in preamble if Blackboard Bold or + // Fraktur used: + if (key_->name == "mathfrak" || key_->name == "mathbb") + features.require("amssymb"); + if (key_->name == "text") + features.require("amsmath"); + if (key_->name == "textipa") + features.require("tipa"); +} + + +void InsetMathFont::infoize(odocstream & os) const +{ + os << "Font: " << key_->name; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathFontOld.C b/src/mathed/InsetMathFontOld.C deleted file mode 100644 index d061280118..0000000000 --- a/src/mathed/InsetMathFontOld.C +++ /dev/null @@ -1,89 +0,0 @@ -/** - * \file InsetMathFontOld.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathFontOld.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathParser.h" -#include "MathStream.h" -#include "support/std_ostream.h" - - -namespace lyx { - -using std::auto_ptr; - - -InsetMathFontOld::InsetMathFontOld(latexkeys const * key) - : InsetMathNest(1), key_(key) -{ - //lock(true); -} - - -auto_ptr InsetMathFontOld::doClone() const -{ - return auto_ptr(new InsetMathFontOld(*this)); -} - - -bool InsetMathFontOld::metrics(MetricsInfo & mi, Dimension & dim) const -{ - FontSetChanger dummy(mi.base, key_->name.c_str()); - cell(0).metrics(mi, dim); - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathFontOld::draw(PainterInfo & pi, int x, int y) const -{ - FontSetChanger dummy(pi.base, key_->name.c_str()); - cell(0).draw(pi, x + 1, y); - drawMarkers(pi, x, y); -} - - -void InsetMathFontOld::metricsT(TextMetricsInfo const & mi, Dimension & dim) const -{ - cell(0).metricsT(mi, dim); -} - - -void InsetMathFontOld::drawT(TextPainter & pain, int x, int y) const -{ - cell(0).drawT(pain, x, y); -} - - -void InsetMathFontOld::write(WriteStream & os) const -{ - os << "{\\" << key_->name << ' ' << cell(0) << '}'; -} - - -void InsetMathFontOld::normalize(NormalStream & os) const -{ - os << "[font " << key_->name << ' ' << cell(0) << ']'; -} - - -void InsetMathFontOld::infoize(odocstream & os) const -{ - os << "Font: " << key_->name; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathFontOld.cpp b/src/mathed/InsetMathFontOld.cpp new file mode 100644 index 0000000000..d061280118 --- /dev/null +++ b/src/mathed/InsetMathFontOld.cpp @@ -0,0 +1,89 @@ +/** + * \file InsetMathFontOld.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathFontOld.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathParser.h" +#include "MathStream.h" +#include "support/std_ostream.h" + + +namespace lyx { + +using std::auto_ptr; + + +InsetMathFontOld::InsetMathFontOld(latexkeys const * key) + : InsetMathNest(1), key_(key) +{ + //lock(true); +} + + +auto_ptr InsetMathFontOld::doClone() const +{ + return auto_ptr(new InsetMathFontOld(*this)); +} + + +bool InsetMathFontOld::metrics(MetricsInfo & mi, Dimension & dim) const +{ + FontSetChanger dummy(mi.base, key_->name.c_str()); + cell(0).metrics(mi, dim); + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathFontOld::draw(PainterInfo & pi, int x, int y) const +{ + FontSetChanger dummy(pi.base, key_->name.c_str()); + cell(0).draw(pi, x + 1, y); + drawMarkers(pi, x, y); +} + + +void InsetMathFontOld::metricsT(TextMetricsInfo const & mi, Dimension & dim) const +{ + cell(0).metricsT(mi, dim); +} + + +void InsetMathFontOld::drawT(TextPainter & pain, int x, int y) const +{ + cell(0).drawT(pain, x, y); +} + + +void InsetMathFontOld::write(WriteStream & os) const +{ + os << "{\\" << key_->name << ' ' << cell(0) << '}'; +} + + +void InsetMathFontOld::normalize(NormalStream & os) const +{ + os << "[font " << key_->name << ' ' << cell(0) << ']'; +} + + +void InsetMathFontOld::infoize(odocstream & os) const +{ + os << "Font: " << key_->name; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathFrac.C b/src/mathed/InsetMathFrac.C deleted file mode 100644 index 924cebe79c..0000000000 --- a/src/mathed/InsetMathFrac.C +++ /dev/null @@ -1,199 +0,0 @@ -/** - * \file InsetMathFrac.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Alejandro Aguilar Sierra - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathFrac.h" -#include "MathData.h" -#include "MathStream.h" -#include "TextPainter.h" -#include "LaTeXFeatures.h" -#include "LColor.h" -#include "frontends/Painter.h" - - -namespace lyx { - - -using std::string; -using std::max; -using std::auto_ptr; - - -InsetMathFrac::InsetMathFrac(Kind kind) - : kind_(kind) -{} - - -auto_ptr InsetMathFrac::doClone() const -{ - return auto_ptr(new InsetMathFrac(*this)); -} - - -InsetMathFrac * InsetMathFrac::asFracInset() -{ - return kind_ == ATOP ? 0 : this; -} - - -InsetMathFrac const * InsetMathFrac::asFracInset() const -{ - return kind_ == ATOP ? 0 : this; -} - - -bool InsetMathFrac::metrics(MetricsInfo & mi, Dimension & dim) const -{ - FracChanger dummy(mi.base); - cell(0).metrics(mi); - cell(1).metrics(mi); - if (kind_ == NICEFRAC) { - dim.wid = cell(0).width() + cell(1).width() + 5; - dim.asc = cell(0).height() + 5; - dim.des = cell(1).height() - 5; - } else { - dim.wid = max(cell(0).width(), cell(1).width()) + 2; - dim.asc = cell(0).height() + 2 + 5; - dim.des = cell(1).height() + 2 - 5; - } - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathFrac::draw(PainterInfo & pi, int x, int y) const -{ - setPosCache(pi, x, y); - int m = x + dim_.wid / 2; - FracChanger dummy(pi.base); - if (kind_ == NICEFRAC) { - cell(0).draw(pi, x + 2, - y - cell(0).descent() - 5); - cell(1).draw(pi, x + cell(0).width() + 5, - y + cell(1).ascent() / 2); - pi.pain.line(x + cell(0).width(), - y + dim_.des - 2, - x + cell(0).width() + 5, - y - dim_.asc + 2, LColor::math); - } else { - cell(0).draw(pi, m - cell(0).width() / 2, - y - cell(0).descent() - 2 - 5); - cell(1).draw(pi, m - cell(1).width() / 2, - y + cell(1).ascent() + 2 - 5); - } - if (kind_ == FRAC || kind_ == OVER) - pi.pain.line(x + 1, y - 5, - x + dim_.wid - 2, y - 5, LColor::math); - drawMarkers(pi, x, y); -} - - -void InsetMathFrac::metricsT(TextMetricsInfo const & mi, Dimension & dim) const -{ - cell(0).metricsT(mi, dim); - cell(1).metricsT(mi, dim); - dim.wid = max(cell(0).width(), cell(1).width()); - dim.asc = cell(0).height() + 1; - dim.des = cell(1).height(); - //dim = dim_; -} - - -void InsetMathFrac::drawT(TextPainter & pain, int x, int y) const -{ - int m = x + dim_.width() / 2; - cell(0).drawT(pain, m - cell(0).width() / 2, y - cell(0).descent() - 1); - cell(1).drawT(pain, m - cell(1).width() / 2, y + cell(1).ascent()); - // ASCII art: ignore niceties - if (kind_ == FRAC || kind_ == OVER || kind_ == NICEFRAC) - pain.horizontalLine(x, y, dim_.width()); -} - - -void InsetMathFrac::write(WriteStream & os) const -{ - switch (kind_) { - case ATOP: - os << '{' << cell(0) << "\\atop " << cell(1) << '}'; - break; - case OVER: - // \\over is only for compatibility, normalize this to \\frac - os << "\\frac{" << cell(0) << "}{" << cell(1) << '}'; - break; - case FRAC: - case NICEFRAC: - InsetMathNest::write(os); - break; - } -} - - -docstring InsetMathFrac::name() const -{ - switch (kind_) { - case FRAC: - return from_ascii("frac"); - case OVER: - return from_ascii("over"); - case NICEFRAC: - return from_ascii("nicefrac"); - case ATOP: - return from_ascii("atop"); - } - // shut up stupid compiler - return docstring(); -} - - -bool InsetMathFrac::extraBraces() const -{ - return kind_ == ATOP || kind_ == OVER; -} - - -void InsetMathFrac::maple(MapleStream & os) const -{ - os << '(' << cell(0) << ")/(" << cell(1) << ')'; -} - - -void InsetMathFrac::mathematica(MathematicaStream & os) const -{ - os << '(' << cell(0) << ")/(" << cell(1) << ')'; -} - - -void InsetMathFrac::octave(OctaveStream & os) const -{ - os << '(' << cell(0) << ")/(" << cell(1) << ')'; -} - - -void InsetMathFrac::mathmlize(MathStream & os) const -{ - os << MTag("mfrac") << cell(0) << cell(1) << ETag("mfrac"); -} - - -void InsetMathFrac::validate(LaTeXFeatures & features) const -{ - if (kind_ == NICEFRAC) - features.require("nicefrac"); - InsetMathNest::validate(features); -} - - - -} // namespace lyx diff --git a/src/mathed/InsetMathFrac.cpp b/src/mathed/InsetMathFrac.cpp new file mode 100644 index 0000000000..924cebe79c --- /dev/null +++ b/src/mathed/InsetMathFrac.cpp @@ -0,0 +1,199 @@ +/** + * \file InsetMathFrac.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Alejandro Aguilar Sierra + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathFrac.h" +#include "MathData.h" +#include "MathStream.h" +#include "TextPainter.h" +#include "LaTeXFeatures.h" +#include "LColor.h" +#include "frontends/Painter.h" + + +namespace lyx { + + +using std::string; +using std::max; +using std::auto_ptr; + + +InsetMathFrac::InsetMathFrac(Kind kind) + : kind_(kind) +{} + + +auto_ptr InsetMathFrac::doClone() const +{ + return auto_ptr(new InsetMathFrac(*this)); +} + + +InsetMathFrac * InsetMathFrac::asFracInset() +{ + return kind_ == ATOP ? 0 : this; +} + + +InsetMathFrac const * InsetMathFrac::asFracInset() const +{ + return kind_ == ATOP ? 0 : this; +} + + +bool InsetMathFrac::metrics(MetricsInfo & mi, Dimension & dim) const +{ + FracChanger dummy(mi.base); + cell(0).metrics(mi); + cell(1).metrics(mi); + if (kind_ == NICEFRAC) { + dim.wid = cell(0).width() + cell(1).width() + 5; + dim.asc = cell(0).height() + 5; + dim.des = cell(1).height() - 5; + } else { + dim.wid = max(cell(0).width(), cell(1).width()) + 2; + dim.asc = cell(0).height() + 2 + 5; + dim.des = cell(1).height() + 2 - 5; + } + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathFrac::draw(PainterInfo & pi, int x, int y) const +{ + setPosCache(pi, x, y); + int m = x + dim_.wid / 2; + FracChanger dummy(pi.base); + if (kind_ == NICEFRAC) { + cell(0).draw(pi, x + 2, + y - cell(0).descent() - 5); + cell(1).draw(pi, x + cell(0).width() + 5, + y + cell(1).ascent() / 2); + pi.pain.line(x + cell(0).width(), + y + dim_.des - 2, + x + cell(0).width() + 5, + y - dim_.asc + 2, LColor::math); + } else { + cell(0).draw(pi, m - cell(0).width() / 2, + y - cell(0).descent() - 2 - 5); + cell(1).draw(pi, m - cell(1).width() / 2, + y + cell(1).ascent() + 2 - 5); + } + if (kind_ == FRAC || kind_ == OVER) + pi.pain.line(x + 1, y - 5, + x + dim_.wid - 2, y - 5, LColor::math); + drawMarkers(pi, x, y); +} + + +void InsetMathFrac::metricsT(TextMetricsInfo const & mi, Dimension & dim) const +{ + cell(0).metricsT(mi, dim); + cell(1).metricsT(mi, dim); + dim.wid = max(cell(0).width(), cell(1).width()); + dim.asc = cell(0).height() + 1; + dim.des = cell(1).height(); + //dim = dim_; +} + + +void InsetMathFrac::drawT(TextPainter & pain, int x, int y) const +{ + int m = x + dim_.width() / 2; + cell(0).drawT(pain, m - cell(0).width() / 2, y - cell(0).descent() - 1); + cell(1).drawT(pain, m - cell(1).width() / 2, y + cell(1).ascent()); + // ASCII art: ignore niceties + if (kind_ == FRAC || kind_ == OVER || kind_ == NICEFRAC) + pain.horizontalLine(x, y, dim_.width()); +} + + +void InsetMathFrac::write(WriteStream & os) const +{ + switch (kind_) { + case ATOP: + os << '{' << cell(0) << "\\atop " << cell(1) << '}'; + break; + case OVER: + // \\over is only for compatibility, normalize this to \\frac + os << "\\frac{" << cell(0) << "}{" << cell(1) << '}'; + break; + case FRAC: + case NICEFRAC: + InsetMathNest::write(os); + break; + } +} + + +docstring InsetMathFrac::name() const +{ + switch (kind_) { + case FRAC: + return from_ascii("frac"); + case OVER: + return from_ascii("over"); + case NICEFRAC: + return from_ascii("nicefrac"); + case ATOP: + return from_ascii("atop"); + } + // shut up stupid compiler + return docstring(); +} + + +bool InsetMathFrac::extraBraces() const +{ + return kind_ == ATOP || kind_ == OVER; +} + + +void InsetMathFrac::maple(MapleStream & os) const +{ + os << '(' << cell(0) << ")/(" << cell(1) << ')'; +} + + +void InsetMathFrac::mathematica(MathematicaStream & os) const +{ + os << '(' << cell(0) << ")/(" << cell(1) << ')'; +} + + +void InsetMathFrac::octave(OctaveStream & os) const +{ + os << '(' << cell(0) << ")/(" << cell(1) << ')'; +} + + +void InsetMathFrac::mathmlize(MathStream & os) const +{ + os << MTag("mfrac") << cell(0) << cell(1) << ETag("mfrac"); +} + + +void InsetMathFrac::validate(LaTeXFeatures & features) const +{ + if (kind_ == NICEFRAC) + features.require("nicefrac"); + InsetMathNest::validate(features); +} + + + +} // namespace lyx diff --git a/src/mathed/InsetMathFracBase.C b/src/mathed/InsetMathFracBase.C deleted file mode 100644 index 22b0befb64..0000000000 --- a/src/mathed/InsetMathFracBase.C +++ /dev/null @@ -1,49 +0,0 @@ -/** - * \file InsetMathFracBase.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathFracBase.h" -#include "MathData.h" -#include "cursor.h" - - -namespace lyx { - - -InsetMathFracBase::InsetMathFracBase() - : InsetMathNest(2) -{} - - -bool InsetMathFracBase::idxRight(LCursor &) const -{ - return false; -} - - -bool InsetMathFracBase::idxLeft(LCursor &) const -{ - return false; -} - - -bool InsetMathFracBase::idxUpDown(LCursor & cur, bool up) const -{ - InsetMath::idx_type target = !up; // up ? 0 : 1, since upper cell has idx 0 - if (cur.idx() == target) - return false; - cur.idx() = target; - cur.pos() = cell(target).x2pos(cur.x_target()); - return true; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathFracBase.cpp b/src/mathed/InsetMathFracBase.cpp new file mode 100644 index 0000000000..22b0befb64 --- /dev/null +++ b/src/mathed/InsetMathFracBase.cpp @@ -0,0 +1,49 @@ +/** + * \file InsetMathFracBase.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathFracBase.h" +#include "MathData.h" +#include "cursor.h" + + +namespace lyx { + + +InsetMathFracBase::InsetMathFracBase() + : InsetMathNest(2) +{} + + +bool InsetMathFracBase::idxRight(LCursor &) const +{ + return false; +} + + +bool InsetMathFracBase::idxLeft(LCursor &) const +{ + return false; +} + + +bool InsetMathFracBase::idxUpDown(LCursor & cur, bool up) const +{ + InsetMath::idx_type target = !up; // up ? 0 : 1, since upper cell has idx 0 + if (cur.idx() == target) + return false; + cur.idx() = target; + cur.pos() = cell(target).x2pos(cur.x_target()); + return true; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathFrameBox.C b/src/mathed/InsetMathFrameBox.C deleted file mode 100644 index e77fe38fc6..0000000000 --- a/src/mathed/InsetMathFrameBox.C +++ /dev/null @@ -1,95 +0,0 @@ -/** - * \file InsetMathFrameBox.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathFrameBox.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathSupport.h" -#include "LColor.h" -#include "frontends/Painter.h" - - -namespace lyx { - -using std::auto_ptr; - - -InsetMathFrameBox::InsetMathFrameBox() - : InsetMathNest(3) -{} - - -auto_ptr InsetMathFrameBox::doClone() const -{ - return auto_ptr(new InsetMathFrameBox(*this)); -} - - -bool InsetMathFrameBox::metrics(MetricsInfo & mi, Dimension & dim) const -{ - FontSetChanger dummy(mi.base, "textnormal"); - w_ = mathed_char_width(mi.base.font, '['); - InsetMathNest::metrics(mi); - dim = cell(0).dim(); - dim += cell(1).dim(); - dim += cell(2).dim(); - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathFrameBox::draw(PainterInfo & pi, int x, int y) const -{ - FontSetChanger dummy(pi.base, "textnormal"); - pi.pain.rectangle(x + 1, y - dim_.ascent() + 1, - dim_.width() - 2, dim_.height() - 2, LColor::foreground); - x += 5; - - drawStrBlack(pi, x, y, from_ascii("[")); - x += w_; - cell(0).draw(pi, x, y); - x += cell(0).width(); - drawStrBlack(pi, x, y, from_ascii("]")); - x += w_ + 4; - - drawStrBlack(pi, x, y, from_ascii("[")); - x += w_; - cell(1).draw(pi, x, y); - x += cell(1).width(); - drawStrBlack(pi, x, y, from_ascii("]")); - x += w_ + 4; - - cell(2).draw(pi, x, y); - drawMarkers(pi, x, y); -} - - -void InsetMathFrameBox::write(WriteStream & os) const -{ - os << "\\framebox"; - os << '[' << cell(0) << ']'; - if (cell(1).size()) - os << '[' << cell(1) << ']'; - os << '{' << cell(2) << '}'; -} - - -void InsetMathFrameBox::normalize(NormalStream & os) const -{ - os << "[framebox " << cell(0) << ' ' << cell(1) << ' ' << cell(2) << ']'; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathFrameBox.cpp b/src/mathed/InsetMathFrameBox.cpp new file mode 100644 index 0000000000..e77fe38fc6 --- /dev/null +++ b/src/mathed/InsetMathFrameBox.cpp @@ -0,0 +1,95 @@ +/** + * \file InsetMathFrameBox.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathFrameBox.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathSupport.h" +#include "LColor.h" +#include "frontends/Painter.h" + + +namespace lyx { + +using std::auto_ptr; + + +InsetMathFrameBox::InsetMathFrameBox() + : InsetMathNest(3) +{} + + +auto_ptr InsetMathFrameBox::doClone() const +{ + return auto_ptr(new InsetMathFrameBox(*this)); +} + + +bool InsetMathFrameBox::metrics(MetricsInfo & mi, Dimension & dim) const +{ + FontSetChanger dummy(mi.base, "textnormal"); + w_ = mathed_char_width(mi.base.font, '['); + InsetMathNest::metrics(mi); + dim = cell(0).dim(); + dim += cell(1).dim(); + dim += cell(2).dim(); + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathFrameBox::draw(PainterInfo & pi, int x, int y) const +{ + FontSetChanger dummy(pi.base, "textnormal"); + pi.pain.rectangle(x + 1, y - dim_.ascent() + 1, + dim_.width() - 2, dim_.height() - 2, LColor::foreground); + x += 5; + + drawStrBlack(pi, x, y, from_ascii("[")); + x += w_; + cell(0).draw(pi, x, y); + x += cell(0).width(); + drawStrBlack(pi, x, y, from_ascii("]")); + x += w_ + 4; + + drawStrBlack(pi, x, y, from_ascii("[")); + x += w_; + cell(1).draw(pi, x, y); + x += cell(1).width(); + drawStrBlack(pi, x, y, from_ascii("]")); + x += w_ + 4; + + cell(2).draw(pi, x, y); + drawMarkers(pi, x, y); +} + + +void InsetMathFrameBox::write(WriteStream & os) const +{ + os << "\\framebox"; + os << '[' << cell(0) << ']'; + if (cell(1).size()) + os << '[' << cell(1) << ']'; + os << '{' << cell(2) << '}'; +} + + +void InsetMathFrameBox::normalize(NormalStream & os) const +{ + os << "[framebox " << cell(0) << ' ' << cell(1) << ' ' << cell(2) << ']'; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathGrid.C b/src/mathed/InsetMathGrid.C deleted file mode 100644 index 53354fa623..0000000000 --- a/src/mathed/InsetMathGrid.C +++ /dev/null @@ -1,1400 +0,0 @@ -/** - * \file InsetMathGrid.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathGrid.h" -#include "MathData.h" -#include "MathParser.h" -#include "MathStream.h" - -#include "BufferView.h" -#include "CutAndPaste.h" -#include "FuncStatus.h" -#include "LColor.h" -#include "cursor.h" -#include "debug.h" -#include "funcrequest.h" -#include "gettext.h" -#include "undo.h" - -#include "frontends/Clipboard.h" -#include "frontends/Painter.h" - -#include "insets/MailInset.h" - -#include "support/lstrings.h" - -#include - - -namespace lyx { - -using support::bformat; - -using std::endl; -using std::max; -using std::min; -using std::swap; - -using std::string; -using std::auto_ptr; -using std::istream; -using std::istringstream; -using std::vector; - -class GridInsetMailer : public MailInset { -public: - GridInsetMailer(InsetMathGrid & inset) : inset_(inset) {} - /// - virtual string const & name() const - { - static string const theName = "tabular"; - return theName; - } - /// - virtual string const inset2string(Buffer const &) const - { - odocstringstream data; - //data << name() << " active_cell " << inset.getActCell() << '\n'; - data << from_utf8(name()) << " active_cell " << 0 << '\n'; - WriteStream ws(data); - inset_.write(ws); - return to_utf8(data.str()); - } - -protected: - InsetBase & inset() const { return inset_; } - InsetMathGrid & inset_; -}; - - -namespace { - -docstring verboseHLine(int n) -{ - docstring res; - for (int i = 0; i < n; ++i) - res += "\\hline"; - if (n) - res += ' '; - return res; -} - - -int extractInt(istream & is) -{ - int num = 1; - is >> num; - return (num == 0) ? 1 : num; -} - -} - - -////////////////////////////////////////////////////////////// - - -InsetMathGrid::CellInfo::CellInfo() - : dummy_(false) -{} - - - - -////////////////////////////////////////////////////////////// - - -InsetMathGrid::RowInfo::RowInfo() - : lines_(0), skip_(0), allow_pagebreak_(true) -{} - - - -int InsetMathGrid::RowInfo::skipPixels() const -{ - return crskip_.inBP(); -} - - - -////////////////////////////////////////////////////////////// - - -InsetMathGrid::ColInfo::ColInfo() - : align_('c'), lines_(0) -{} - - -////////////////////////////////////////////////////////////// - - -InsetMathGrid::InsetMathGrid(char v, docstring const & h) - : InsetMathNest(guessColumns(h)), - rowinfo_(2), - colinfo_(guessColumns(h) + 1), - cellinfo_(1 * guessColumns(h)) -{ - setDefaults(); - valign(v); - halign(h); - //lyxerr << "created grid with " << ncols() << " columns" << endl; -} - - -InsetMathGrid::InsetMathGrid() - : InsetMathNest(1), - rowinfo_(1 + 1), - colinfo_(1 + 1), - cellinfo_(1), - v_align_('c') -{ - setDefaults(); -} - - -InsetMathGrid::InsetMathGrid(col_type m, row_type n) - : InsetMathNest(m * n), - rowinfo_(n + 1), - colinfo_(m + 1), - cellinfo_(m * n), - v_align_('c') -{ - setDefaults(); -} - - -InsetMathGrid::InsetMathGrid(col_type m, row_type n, char v, docstring const & h) - : InsetMathNest(m * n), - rowinfo_(n + 1), - colinfo_(m + 1), - cellinfo_(m * n), - v_align_(v) -{ - setDefaults(); - valign(v); - halign(h); -} - - -auto_ptr InsetMathGrid::doClone() const -{ - return auto_ptr(new InsetMathGrid(*this)); -} - - -InsetMath::idx_type InsetMathGrid::index(row_type row, col_type col) const -{ - return col + ncols() * row; -} - - -void InsetMathGrid::setDefaults() -{ - if (ncols() <= 0) - lyxerr << "positive number of columns expected" << endl; - //if (nrows() <= 0) - // lyxerr << "positive number of rows expected" << endl; - for (col_type col = 0; col < ncols(); ++col) { - colinfo_[col].align_ = defaultColAlign(col); - colinfo_[col].skip_ = defaultColSpace(col); - } -} - - -void InsetMathGrid::halign(docstring const & hh) -{ - col_type col = 0; - for (docstring::const_iterator it = hh.begin(); it != hh.end(); ++it) { - char_type c = *it; - if (c == '|') { - colinfo_[col].lines_++; - } else if (col >= ncols()) { - // Only '|' is allowed in the last dummy column - break; - } else if (c == 'c' || c == 'l' || c == 'r') { - colinfo_[col].align_ = (char)c; - ++col; - colinfo_[col].lines_ = 0; - } else { - lyxerr << "unknown column separator: '" << c << "'" << endl; - } - } - -/* - col_type n = hh.size(); - if (n > ncols()) - n = ncols(); - for (col_type col = 0; col < n; ++col) - colinfo_[col].align_ = hh[col]; -*/ -} - - -InsetMathGrid::col_type InsetMathGrid::guessColumns(docstring const & hh) const -{ - col_type col = 0; - for (docstring::const_iterator it = hh.begin(); it != hh.end(); ++it) - if (*it == 'c' || *it == 'l' || *it == 'r') - ++col; - // let's have at least one column, even if we did not recognize its - // alignment - if (col == 0) - col = 1; - return col; -} - - -void InsetMathGrid::halign(char h, col_type col) -{ - colinfo_[col].align_ = h; -} - - -char InsetMathGrid::halign(col_type col) const -{ - return colinfo_[col].align_; -} - - -docstring InsetMathGrid::halign() const -{ - docstring res; - for (col_type col = 0; col < ncols(); ++col) { - res += docstring(colinfo_[col].lines_, '|'); - res += colinfo_[col].align_; - } - return res + docstring(colinfo_[ncols()].lines_, '|'); -} - - -void InsetMathGrid::valign(char c) -{ - v_align_ = c; -} - - -char InsetMathGrid::valign() const -{ - return v_align_; -} - - -InsetMathGrid::col_type InsetMathGrid::ncols() const -{ - return colinfo_.size() - 1; -} - - -InsetMathGrid::row_type InsetMathGrid::nrows() const -{ - return rowinfo_.size() - 1; -} - - -InsetMathGrid::col_type InsetMathGrid::col(idx_type idx) const -{ - return idx % ncols(); -} - - -InsetMathGrid::row_type InsetMathGrid::row(idx_type idx) const -{ - return idx / ncols(); -} - - -void InsetMathGrid::vcrskip(LyXLength const & crskip, row_type row) -{ - rowinfo_[row].crskip_ = crskip; -} - - -LyXLength InsetMathGrid::vcrskip(row_type row) const -{ - return rowinfo_[row].crskip_; -} - - -void InsetMathGrid::metrics(MetricsInfo & mi) const -{ - // let the cells adjust themselves - InsetMathNest::metrics(mi); - - // compute absolute sizes of vertical structure - for (row_type row = 0; row < nrows(); ++row) { - int asc = 0; - int desc = 0; - for (col_type col = 0; col < ncols(); ++col) { - MathArray const & c = cell(index(row, col)); - asc = max(asc, c.ascent()); - desc = max(desc, c.descent()); - } - rowinfo_[row].ascent_ = asc; - rowinfo_[row].descent_ = desc; - } - rowinfo_[0].ascent_ += hlinesep() * rowinfo_[0].lines_; - rowinfo_[nrows()].ascent_ = 0; - rowinfo_[nrows()].descent_ = 0; - - // compute vertical offsets - rowinfo_[0].offset_ = 0; - for (row_type row = 1; row <= nrows(); ++row) { - rowinfo_[row].offset_ = - rowinfo_[row - 1].offset_ + - rowinfo_[row - 1].descent_ + - rowinfo_[row - 1].skipPixels() + - rowsep() + - rowinfo_[row].lines_ * hlinesep() + - rowinfo_[row].ascent_; - } - - // adjust vertical offset - int h = 0; - switch (v_align_) { - case 't': - h = 0; - break; - case 'b': - h = rowinfo_[nrows() - 1].offset_; - break; - default: - h = rowinfo_[nrows() - 1].offset_ / 2; - } - for (row_type row = 0; row <= nrows(); ++row) - rowinfo_[row].offset_ -= h; - - - // compute absolute sizes of horizontal structure - for (col_type col = 0; col < ncols(); ++col) { - int wid = 0; - for (row_type row = 0; row < nrows(); ++row) - wid = max(wid, cell(index(row, col)).width()); - colinfo_[col].width_ = wid; - } - colinfo_[ncols()].width_ = 0; - - // compute horizontal offsets - colinfo_[0].offset_ = border(); - for (col_type col = 1; col <= ncols(); ++col) { - colinfo_[col].offset_ = - colinfo_[col - 1].offset_ + - colinfo_[col - 1].width_ + - colinfo_[col - 1].skip_ + - colsep() + - colinfo_[col].lines_ * vlinesep(); - } - - - dim_.wid = colinfo_[ncols() - 1].offset_ - + colinfo_[ncols() - 1].width_ - + vlinesep() * colinfo_[ncols()].lines_ - + border(); - - dim_.asc = - rowinfo_[0].offset_ - + rowinfo_[0].ascent_ - + hlinesep() * rowinfo_[0].lines_ - + border(); - - dim_.des = rowinfo_[nrows() - 1].offset_ - + rowinfo_[nrows() - 1].descent_ - + hlinesep() * rowinfo_[nrows()].lines_ - + border(); - - -/* - // Increase ws_[i] for 'R' columns (except the first one) - for (int i = 1; i < nc_; ++i) - if (align_[i] == 'R') - ws_[i] += 10 * df_width; - // Increase ws_[i] for 'C' column - if (align_[0] == 'C') - if (ws_[0] < 7 * workwidth / 8) - ws_[0] = 7 * workwidth / 8; - - // Adjust local tabs - width = colsep(); - for (cxrow = row_.begin(); cxrow; ++cxrow) { - int rg = COLSEP; - int lf = 0; - for (int i = 0; i < nc_; ++i) { - bool isvoid = false; - if (cxrow->getTab(i) <= 0) { - cxrow->setTab(i, df_width); - isvoid = true; - } - switch (align_[i]) { - case 'l': - lf = 0; - break; - case 'c': - lf = (ws_[i] - cxrow->getTab(i))/2; - break; - case 'r': - case 'R': - lf = ws_[i] - cxrow->getTab(i); - break; - case 'C': - if (cxrow == row_.begin()) - lf = 0; - else if (cxrow.is_last()) - lf = ws_[i] - cxrow->getTab(i); - else - lf = (ws_[i] - cxrow->getTab(i))/2; - break; - } - int const ww = (isvoid) ? lf : lf + cxrow->getTab(i); - cxrow->setTab(i, lf + rg); - rg = ws_[i] - ww + colsep(); - if (cxrow == row_.begin()) - width += ws_[i] + colsep(); - } - cxrow->setBaseline(cxrow->getBaseline() - ascent); - } -*/ - metricsMarkers2(dim_); -} - - -bool InsetMathGrid::metrics(MetricsInfo & mi, Dimension & dim) const -{ - dim = dim_; - metrics(mi); - if (dim_ == dim) - return false; - dim = dim_; - return true; -} - - -void InsetMathGrid::draw(PainterInfo & pi, int x, int y) const -{ - drawWithMargin(pi, x, y, 0, 0); -} - -void InsetMathGrid::drawWithMargin(PainterInfo & pi, int x, int y, - int lmargin, int rmargin) const -{ - for (idx_type idx = 0; idx < nargs(); ++idx) - cell(idx).draw(pi, x + lmargin + cellXOffset(idx), - y + cellYOffset(idx)); - - for (row_type row = 0; row <= nrows(); ++row) - for (unsigned int i = 0; i < rowinfo_[row].lines_; ++i) { - int yy = y + rowinfo_[row].offset_ - rowinfo_[row].ascent_ - - i * hlinesep() - hlinesep()/2 - rowsep()/2; - pi.pain.line(x + lmargin + 1, yy, - x + dim_.width() - rmargin - 1, yy, - LColor::foreground); - } - - for (col_type col = 0; col <= ncols(); ++col) - for (unsigned int i = 0; i < colinfo_[col].lines_; ++i) { - int xx = x + lmargin + colinfo_[col].offset_ - - i * vlinesep() - vlinesep()/2 - colsep()/2; - pi.pain.line(xx, y - dim_.ascent() + 1, - xx, y + dim_.descent() - 1, - LColor::foreground); - } - drawMarkers2(pi, x, y); -} - - -void InsetMathGrid::metricsT(TextMetricsInfo const & mi, Dimension & dim) const -{ - // let the cells adjust themselves - //InsetMathNest::metrics(mi); - for (idx_type i = 0; i < nargs(); ++i) - cell(i).metricsT(mi, dim); - - // compute absolute sizes of vertical structure - for (row_type row = 0; row < nrows(); ++row) { - int asc = 0; - int desc = 0; - for (col_type col = 0; col < ncols(); ++col) { - MathArray const & c = cell(index(row, col)); - asc = max(asc, c.ascent()); - desc = max(desc, c.descent()); - } - rowinfo_[row].ascent_ = asc; - rowinfo_[row].descent_ = desc; - } - //rowinfo_[0].ascent_ += hlinesep() * rowinfo_[0].lines_; - rowinfo_[nrows()].ascent_ = 0; - rowinfo_[nrows()].descent_ = 0; - - // compute vertical offsets - rowinfo_[0].offset_ = 0; - for (row_type row = 1; row <= nrows(); ++row) { - rowinfo_[row].offset_ = - rowinfo_[row - 1].offset_ + - rowinfo_[row - 1].descent_ + - //rowinfo_[row - 1].skipPixels() + - 1 + //rowsep() + - //rowinfo_[row].lines_ * hlinesep() + - rowinfo_[row].ascent_; - } - - // adjust vertical offset - int h = 0; - switch (v_align_) { - case 't': - h = 0; - break; - case 'b': - h = rowinfo_[nrows() - 1].offset_; - break; - default: - h = rowinfo_[nrows() - 1].offset_ / 2; - } - for (row_type row = 0; row <= nrows(); ++row) - rowinfo_[row].offset_ -= h; - - - // compute absolute sizes of horizontal structure - for (col_type col = 0; col < ncols(); ++col) { - int wid = 0; - for (row_type row = 0; row < nrows(); ++row) - wid = max(wid, cell(index(row, col)).width()); - colinfo_[col].width_ = wid; - } - colinfo_[ncols()].width_ = 0; - - // compute horizontal offsets - colinfo_[0].offset_ = border(); - for (col_type col = 1; col <= ncols(); ++col) { - colinfo_[col].offset_ = - colinfo_[col - 1].offset_ + - colinfo_[col - 1].width_ + - colinfo_[col - 1].skip_ + - 1 ; //colsep() + - //colinfo_[col].lines_ * vlinesep(); - } - - - dim.wid = colinfo_[ncols() - 1].offset_ - + colinfo_[ncols() - 1].width_ - //+ vlinesep() * colinfo_[ncols()].lines_ - + 2; - - dim.asc = -rowinfo_[0].offset_ - + rowinfo_[0].ascent_ - //+ hlinesep() * rowinfo_[0].lines_ - + 1; - - dim.des = rowinfo_[nrows() - 1].offset_ - + rowinfo_[nrows() - 1].descent_ - //+ hlinesep() * rowinfo_[nrows()].lines_ - + 1; -} - - -void InsetMathGrid::drawT(TextPainter & pain, int x, int y) const -{ - for (idx_type idx = 0; idx < nargs(); ++idx) - cell(idx).drawT(pain, x + cellXOffset(idx), y + cellYOffset(idx)); -} - - -docstring InsetMathGrid::eolString(row_type row, bool emptyline, bool fragile) const -{ - docstring eol; - - if (!rowinfo_[row].crskip_.zero()) - eol += '[' + from_utf8(rowinfo_[row].crskip_.asLatexString()) + ']'; - else if(!rowinfo_[row].allow_pagebreak_) - eol += '*'; - - // make sure an upcoming '[' does not break anything - if (row + 1 < nrows()) { - MathArray const & c = cell(index(row + 1, 0)); - if (c.size() && c.front()->getChar() == '[') - //eol += "[0pt]"; - eol += "{}"; - } - - // only add \\ if necessary - if (eol.empty() && row + 1 == nrows() && (nrows() == 1 || !emptyline)) - return docstring(); - - return (fragile ? "\\protect\\\\" : "\\\\") + eol; -} - - -docstring InsetMathGrid::eocString(col_type col, col_type lastcol) const -{ - if (col + 1 == lastcol) - return docstring(); - return from_ascii(" & "); -} - - -void InsetMathGrid::addRow(row_type row) -{ - rowinfo_.insert(rowinfo_.begin() + row + 1, RowInfo()); - cells_.insert - (cells_.begin() + (row + 1) * ncols(), ncols(), MathArray()); - cellinfo_.insert - (cellinfo_.begin() + (row + 1) * ncols(), ncols(), CellInfo()); -} - - -void InsetMathGrid::appendRow() -{ - rowinfo_.push_back(RowInfo()); - //cells_.insert(cells_.end(), ncols(), MathArray()); - for (col_type col = 0; col < ncols(); ++col) { - cells_.push_back(cells_type::value_type()); - cellinfo_.push_back(CellInfo()); - } -} - - -void InsetMathGrid::delRow(row_type row) -{ - if (nrows() == 1) - return; - - cells_type::iterator it = cells_.begin() + row * ncols(); - cells_.erase(it, it + ncols()); - - vector::iterator jt = cellinfo_.begin() + row * ncols(); - cellinfo_.erase(jt, jt + ncols()); - - rowinfo_.erase(rowinfo_.begin() + row); -} - - -void InsetMathGrid::copyRow(row_type row) -{ - addRow(row); - for (col_type col = 0; col < ncols(); ++col) - cells_[(row + 1) * ncols() + col] = cells_[row * ncols() + col]; -} - - -void InsetMathGrid::swapRow(row_type row) -{ - if (nrows() == 1) - return; - if (row + 1 == nrows()) - --row; - for (col_type col = 0; col < ncols(); ++col) - swap(cells_[row * ncols() + col], cells_[(row + 1) * ncols() + col]); -} - - -void InsetMathGrid::addCol(col_type newcol) -{ - const col_type nc = ncols(); - const row_type nr = nrows(); - cells_type new_cells((nc + 1) * nr); - vector new_cellinfo((nc + 1) * nr); - - for (row_type row = 0; row < nr; ++row) - for (col_type col = 0; col < nc; ++col) { - new_cells[row * (nc + 1) + col + (col > newcol)] - = cells_[row * nc + col]; - new_cellinfo[row * (nc + 1) + col + (col > newcol)] - = cellinfo_[row * nc + col]; - } - swap(cells_, new_cells); - swap(cellinfo_, new_cellinfo); - - ColInfo inf; - inf.skip_ = defaultColSpace(newcol); - inf.align_ = defaultColAlign(newcol); - colinfo_.insert(colinfo_.begin() + newcol, inf); -} - - -void InsetMathGrid::delCol(col_type col) -{ - if (ncols() == 1) - return; - - cells_type tmpcells; - vector tmpcellinfo; - for (col_type i = 0; i < nargs(); ++i) - if (i % ncols() != col) { - tmpcells.push_back(cells_[i]); - tmpcellinfo.push_back(cellinfo_[i]); - } - swap(cells_, tmpcells); - swap(cellinfo_, tmpcellinfo); - - colinfo_.erase(colinfo_.begin() + col); -} - - -void InsetMathGrid::copyCol(col_type col) -{ - addCol(col); - for (row_type row = 0; row < nrows(); ++row) - cells_[row * ncols() + col + 1] = cells_[row * ncols() + col]; -} - - -void InsetMathGrid::swapCol(col_type col) -{ - if (ncols() == 1) - return; - if (col + 1 == ncols()) - --col; - for (row_type row = 0; row < nrows(); ++row) - swap(cells_[row * ncols() + col], cells_[row * ncols() + col + 1]); -} - - -int InsetMathGrid::cellXOffset(idx_type idx) const -{ - col_type c = col(idx); - int x = colinfo_[c].offset_; - char align = colinfo_[c].align_; - if (align == 'r' || align == 'R') - x += colinfo_[c].width_ - cell(idx).width(); - if (align == 'c' || align == 'C') - x += (colinfo_[c].width_ - cell(idx).width()) / 2; - return x; -} - - -int InsetMathGrid::cellYOffset(idx_type idx) const -{ - return rowinfo_[row(idx)].offset_; -} - - -bool InsetMathGrid::idxUpDown(LCursor & cur, bool up) const -{ - if (up) { - if (cur.row() == 0) - return false; - cur.idx() -= ncols(); - } else { - if (cur.row() + 1 >= nrows()) - return false; - cur.idx() += ncols(); - } - cur.pos() = cur.cell().x2pos(cur.x_target() - cur.cell().xo(cur.bv())); - return true; -} - - -bool InsetMathGrid::idxLeft(LCursor & cur) const -{ - // leave matrix if on the left hand edge - if (cur.col() == 0) - return false; - --cur.idx(); - cur.pos() = cur.lastpos(); - return true; -} - - -bool InsetMathGrid::idxRight(LCursor & cur) const -{ - // leave matrix if on the right hand edge - if (cur.col() + 1 == ncols()) - return false; - ++cur.idx(); - cur.pos() = 0; - return true; -} - - -bool InsetMathGrid::idxFirst(LCursor & cur) const -{ - switch (v_align_) { - case 't': - cur.idx() = 0; - break; - case 'b': - cur.idx() = (nrows() - 1) * ncols(); - break; - default: - cur.idx() = ((nrows() - 1) / 2) * ncols(); - } - cur.pos() = 0; - return true; -} - - -bool InsetMathGrid::idxLast(LCursor & cur) const -{ - switch (v_align_) { - case 't': - cur.idx() = ncols() - 1; - break; - case 'b': - cur.idx() = nargs() - 1; - break; - default: - cur.idx() = ((nrows() - 1) / 2 + 1) * ncols() - 1; - } - cur.pos() = cur.lastpos(); - return true; -} - - -bool InsetMathGrid::idxDelete(idx_type & idx) -{ - // nothing to do if we have just one row - if (nrows() == 1) - return false; - - // nothing to do if we are in the middle of the last row of the inset - if (idx + ncols() > nargs()) - return false; - - // try to delete entire sequence of ncols() empty cells if possible - for (idx_type i = idx; i < idx + ncols(); ++i) - if (cell(i).size()) - return false; - - // move cells if necessary - for (idx_type i = index(row(idx), 0); i < idx; ++i) - swap(cell(i), cell(i + ncols())); - - delRow(row(idx)); - - if (idx >= nargs()) - idx = nargs() - 1; - - // undo effect of Ctrl-Tab (i.e. pull next cell) - //if (idx + 1 != nargs()) - // cell(idx).swap(cell(idx + 1)); - - // we handled the event.. - return true; -} - - -// reimplement old behaviour when pressing Delete in the last position -// of a cell -void InsetMathGrid::idxGlue(idx_type idx) -{ - col_type c = col(idx); - if (c + 1 == ncols()) { - if (row(idx) + 1 != nrows()) { - for (col_type cc = 0; cc < ncols(); ++cc) - cell(idx).append(cell(idx + cc + 1)); - delRow(row(idx) + 1); - } - } else { - cell(idx).append(cell(idx + 1)); - for (col_type cc = c + 2; cc < ncols(); ++cc) - cell(idx - c + cc - 1) = cell(idx - c + cc); - cell(idx - c + ncols() - 1).clear(); - } -} - - -InsetMathGrid::RowInfo const & InsetMathGrid::rowinfo(row_type row) const -{ - return rowinfo_[row]; -} - - -InsetMathGrid::RowInfo & InsetMathGrid::rowinfo(row_type row) -{ - return rowinfo_[row]; -} - - -bool InsetMathGrid::idxBetween(idx_type idx, idx_type from, idx_type to) const -{ - row_type const ri = row(idx); - row_type const r1 = min(row(from), row(to)); - row_type const r2 = max(row(from), row(to)); - col_type const ci = col(idx); - col_type const c1 = min(col(from), col(to)); - col_type const c2 = max(col(from), col(to)); - return r1 <= ri && ri <= r2 && c1 <= ci && ci <= c2; -} - - - -void InsetMathGrid::normalize(NormalStream & os) const -{ - os << "[grid "; - for (row_type row = 0; row < nrows(); ++row) { - os << "[row "; - for (col_type col = 0; col < ncols(); ++col) - os << "[cell " << cell(index(row, col)) << ']'; - os << ']'; - } - os << ']'; -} - - -void InsetMathGrid::mathmlize(MathStream & os) const -{ - os << MTag("mtable"); - for (row_type row = 0; row < nrows(); ++row) { - os << MTag("mtr"); - for (col_type col = 0; col < ncols(); ++col) - os << cell(index(row, col)); - os << ETag("mtr"); - } - os << ETag("mtable"); -} - - -void InsetMathGrid::write(WriteStream & os) const -{ - docstring eol; - for (row_type row = 0; row < nrows(); ++row) { - os << verboseHLine(rowinfo_[row].lines_); - // don't write & and empty cells at end of line - col_type lastcol = 0; - bool emptyline = true; - for (col_type col = 0; col < ncols(); ++col) - if (!cell(index(row, col)).empty()) { - lastcol = col + 1; - emptyline = false; - } - for (col_type col = 0; col < lastcol; ++col) - os << cell(index(row, col)) << eocString(col, lastcol); - eol = eolString(row, emptyline, os.fragile()); - os << eol; - // append newline only if line wasn't completely empty - // and this was not the last line in the grid - if (!emptyline && row + 1 < nrows()) - os << "\n"; - } - docstring const s = verboseHLine(rowinfo_[nrows()].lines_); - if (!s.empty()) { - if (eol.empty()) { - if (os.fragile()) - os << "\\protect"; - os << "\\\\"; - } - os << s; - } -} - - -int InsetMathGrid::colsep() const -{ - return 6; -} - - -int InsetMathGrid::rowsep() const -{ - return 6; -} - - -int InsetMathGrid::hlinesep() const -{ - return 3; -} - - -int InsetMathGrid::vlinesep() const -{ - return 3; -} - - -int InsetMathGrid::border() const -{ - return 1; -} - - -void InsetMathGrid::splitCell(LCursor & cur) -{ - if (cur.idx() == cur.lastidx()) - return; - MathArray ar = cur.cell(); - ar.erase(0, cur.pos()); - cur.cell().erase(cur.pos(), cur.lastpos()); - ++cur.idx(); - cur.pos() = 0; - cur.cell().insert(0, ar); -} - - -void InsetMathGrid::doDispatch(LCursor & cur, FuncRequest & cmd) -{ - //lyxerr << "*** InsetMathGrid: request: " << cmd << endl; - switch (cmd.action) { - - case LFUN_MOUSE_RELEASE: - //if (cmd.button() == mouse_button::button3) { - // GridInsetMailer(*this).showDialog(); - // return DispatchResult(true, true); - //} - InsetMathNest::doDispatch(cur, cmd); - break; - - case LFUN_INSET_DIALOG_UPDATE: - GridInsetMailer(*this).updateDialog(&cur.bv()); - break; - - // insert file functions - case LFUN_LINE_DELETE: - // FIXME: We use recordUndoInset when a change reflects more - // than one cell, because recordUndo does not work for - // multiple cells. Unfortunately this puts the cursor in front - // of the inset after undo. This is (especilally for large - // grids) annoying. - recordUndoInset(cur); - //autocorrect_ = false; - //macroModeClose(); - //if (selection_) { - // selDel(); - // break; - //} - if (nrows() > 1) - delRow(cur.row()); - if (cur.idx() > cur.lastidx()) - cur.idx() = cur.lastidx(); - if (cur.pos() > cur.lastpos()) - cur.pos() = cur.lastpos(); - break; - - case LFUN_CELL_SPLIT: - recordUndo(cur); - splitCell(cur); - break; - - case LFUN_CELL_BACKWARD: - // See below. - cur.selection() = false; - if (!idxPrev(cur)) { - cmd = FuncRequest(LFUN_FINISHED_LEFT); - cur.undispatched(); - } - break; - - case LFUN_CELL_FORWARD: - // Can't handle selection by additional 'shift' as this is - // hard bound to LFUN_CELL_BACKWARD - cur.selection() = false; - if (!idxNext(cur)) { - cmd = FuncRequest(LFUN_FINISHED_RIGHT); - cur.undispatched(); - } - break; - - case LFUN_BREAK_LINE: { - recordUndoInset(cur); - row_type const r = cur.row(); - addRow(r); - - // split line - for (col_type c = col(cur.idx()) + 1; c < ncols(); ++c) - swap(cell(index(r, c)), cell(index(r + 1, c))); - - // split cell - splitCell(cur); - swap(cell(cur.idx()), cell(cur.idx() + ncols() - 1)); - if (cur.idx() > 0) - --cur.idx(); - cur.pos() = cur.lastpos(); - - //mathcursor->normalize(); - //cmd = FuncRequest(LFUN_FINISHED_LEFT); - break; - } - - case LFUN_TABULAR_FEATURE: { - recordUndoInset(cur); - //lyxerr << "handling tabular-feature " << to_utf8(cmd.argument()) << endl; - istringstream is(to_utf8(cmd.argument())); - string s; - is >> s; - if (s == "valign-top") - valign('t'); - else if (s == "valign-middle") - valign('c'); - else if (s == "valign-bottom") - valign('b'); - else if (s == "align-left") - halign('l', cur.col()); - else if (s == "align-right") - halign('r', cur.col()); - else if (s == "align-center") - halign('c', cur.col()); - else if (s == "append-row") - for (int i = 0, n = extractInt(is); i < n; ++i) - addRow(cur.row()); - else if (s == "delete-row") { - for (int i = 0, n = extractInt(is); i < n; ++i) { - delRow(cur.row()); - if (cur.idx() >= nargs()) - cur.idx() -= ncols(); - } - cur.pos() = 0; // trick, see below - } - else if (s == "copy-row") { - // Here (as later) we save the cursor col/row - // in order to restore it after operation. - row_type const r = cur.row(); - col_type const c = cur.col(); - for (int i = 0, n = extractInt(is); i < n; ++i) - copyRow(cur.row()); - cur.idx() = index(r, c); - } - else if (s == "swap-row") { - swapRow(cur.row()); - // Trick to suppress same-idx-means-different-cell - // assertion crash: - cur.pos() = 0; - } - else if (s == "add-hline-above") - rowinfo_[cur.row()].lines_++; - else if (s == "add-hline-below") - rowinfo_[cur.row()+1].lines_++; - else if (s == "delete-hline-above") - rowinfo_[cur.row()].lines_--; - else if (s == "delete-hline-below") - rowinfo_[cur.row()+1].lines_--; - else if (s == "append-column") { - row_type const r = cur.row(); - col_type const c = cur.col(); - for (int i = 0, n = extractInt(is); i < n; ++i) - addCol(cur.col()); - cur.idx() = index(r, c); - } - else if (s == "delete-column") { - row_type const r = cur.row(); - col_type const c = cur.col(); - for (int i = 0, n = extractInt(is); i < n; ++i) - delCol(col(cur.idx())); - cur.idx() = index(r, min(c, cur.ncols() - 1)); - cur.pos() = 0; // trick, see above - } - else if (s == "copy-column") { - row_type const r = cur.row(); - col_type const c = cur.col(); - copyCol(cur.col()); - cur.idx() = index(r, c); - } - else if (s == "swap-column") { - swapCol(cur.col()); - cur.pos() = 0; // trick, see above - } - else if (s == "add-vline-left") - colinfo_[cur.col()].lines_++; - else if (s == "add-vline-right") - colinfo_[cur.col()+1].lines_++; - else if (s == "delete-vline-left") - colinfo_[cur.col()].lines_--; - else if (s == "delete-vline-right") - colinfo_[cur.col()+1].lines_--; - else { - cur.undispatched(); - break; - } - lyxerr << "returning FINISHED_LEFT" << endl; - break; - } - - case LFUN_PASTE: { - cur.message(_("Paste")); - cap::replaceSelection(cur); - docstring topaste; - if (cmd.argument().empty() && !theClipboard().isInternal()) - topaste = theClipboard().getAsText(); - else { - idocstringstream is(cmd.argument()); - int n = 0; - is >> n; - topaste = cap::getSelection(cur.buffer(), n); - } - InsetMathGrid grid(1, 1); - if (!topaste.empty()) - mathed_parse_normal(grid, topaste); - - if (grid.nargs() == 1) { - // single cell/part of cell - recordUndo(cur); - cur.cell().insert(cur.pos(), grid.cell(0)); - cur.pos() += grid.cell(0).size(); - } else { - // multiple cells - recordUndoInset(cur); - col_type const numcols = - min(grid.ncols(), ncols() - col(cur.idx())); - row_type const numrows = - min(grid.nrows(), nrows() - cur.row()); - for (row_type r = 0; r < numrows; ++r) { - for (col_type c = 0; c < numcols; ++c) { - idx_type i = index(r + cur.row(), c + col(cur.idx())); - cell(i).insert(0, grid.cell(grid.index(r, c))); - } - // append the left over horizontal cells to the last column - idx_type i = index(r + cur.row(), ncols() - 1); - for (InsetMath::col_type c = numcols; c < grid.ncols(); ++c) - cell(i).append(grid.cell(grid.index(r, c))); - } - // append the left over vertical cells to the last _cell_ - idx_type i = nargs() - 1; - for (row_type r = numrows; r < grid.nrows(); ++r) - for (col_type c = 0; c < grid.ncols(); ++c) - cell(i).append(grid.cell(grid.index(r, c))); - } - cur.clearSelection(); // bug 393 - cur.bv().switchKeyMap(); - finishUndo(); - break; - } - - case LFUN_LINE_BEGIN_SELECT: - case LFUN_LINE_BEGIN: - case LFUN_WORD_BACKWARD_SELECT: - case LFUN_WORD_BACKWARD: - cur.selHandle(cmd.action == LFUN_WORD_BACKWARD_SELECT || - cmd.action == LFUN_LINE_BEGIN_SELECT); - cur.macroModeClose(); - if (cur.pos() != 0) { - cur.pos() = 0; - } else if (cur.idx() % cur.ncols() != 0) { - cur.idx() -= cur.idx() % cur.ncols(); - cur.pos() = 0; - } else if (cur.idx() != 0) { - cur.idx() = 0; - cur.pos() = 0; - } else { - cmd = FuncRequest(LFUN_FINISHED_LEFT); - cur.undispatched(); - } - break; - - case LFUN_WORD_FORWARD_SELECT: - case LFUN_WORD_FORWARD: - case LFUN_LINE_END_SELECT: - case LFUN_LINE_END: - cur.selHandle(cmd.action == LFUN_WORD_FORWARD_SELECT || - cmd.action == LFUN_LINE_END_SELECT); - cur.macroModeClose(); - cur.clearTargetX(); - if (cur.pos() != cur.lastpos()) { - cur.pos() = cur.lastpos(); - } else if ((cur.idx() + 1) % cur.ncols() != 0) { - cur.idx() += cur.ncols() - 1 - cur.idx() % cur.ncols(); - cur.pos() = cur.lastpos(); - } else if (cur.idx() != cur.lastidx()) { - cur.idx() = cur.lastidx(); - cur.pos() = cur.lastpos(); - } else { - cmd = FuncRequest(LFUN_FINISHED_RIGHT); - cur.undispatched(); - } - break; - - default: - InsetMathNest::doDispatch(cur, cmd); - } -} - - -bool InsetMathGrid::getStatus(LCursor & cur, FuncRequest const & cmd, - FuncStatus & status) const -{ - switch (cmd.action) { - case LFUN_TABULAR_FEATURE: { - string const s = to_utf8(cmd.argument()); - if (nrows() <= 1 && (s == "delete-row" || s == "swap-row")) { - status.enabled(false); - status.message(from_utf8(N_("Only one row"))); - return true; - } - if (ncols() <= 1 && - (s == "delete-column" || s == "swap-column")) { - status.enabled(false); - status.message(from_utf8(N_("Only one column"))); - return true; - } - if ((rowinfo_[cur.row()].lines_ == 0 && - s == "delete-hline-above") || - (rowinfo_[cur.row() + 1].lines_ == 0 && - s == "delete-hline-below")) { - status.enabled(false); - status.message(from_utf8(N_("No hline to delete"))); - return true; - } - - if ((colinfo_[cur.col()].lines_ == 0 && - s == "delete-vline-left") || - (colinfo_[cur.col() + 1].lines_ == 0 && - s == "delete-vline-right")) { - status.enabled(false); - status.message(from_utf8(N_("No vline to delete"))); - return true; - } - if (s == "valign-top" || s == "valign-middle" || - s == "valign-bottom" || s == "align-left" || - s == "align-right" || s == "align-center" || - s == "append-row" || s == "delete-row" || - s == "copy-row" || s == "swap-row" || - s == "add-hline-above" || s == "add-hline-below" || - s == "delete-hline-above" || s == "delete-hline-below" || - s == "append-column" || s == "delete-column" || - s == "copy-column" || s == "swap-column" || - s == "add-vline-left" || s == "add-vline-right" || - s == "delete-vline-left" || s == "delete-vline-right") - status.enabled(true); - else { - status.enabled(false); - status.message(bformat( - from_utf8(N_("Unknown tabular feature '%1$s'")), lyx::from_ascii(s))); - } - - status.setOnOff(s == "align-left" && halign(cur.col()) == 'l' - || s == "align-right" && halign(cur.col()) == 'r' - || s == "align-center" && halign(cur.col()) == 'c' - || s == "valign-top" && valign() == 't' - || s == "valign-bottom" && valign() == 'b' - || s == "valign-middle" && valign() == 'm'); - -#if 0 - // FIXME: What did this code do? - // Please check whether it is still needed! - // should be more precise - if (v_align_ == '\0') { - status.enable(true); - break; - } - if (cmd.argument().empty()) { - status.enable(false); - break; - } - if (!support::contains("tcb", cmd.argument()[0])) { - status.enable(false); - break; - } - status.setOnOff(cmd.argument()[0] == v_align_); - status.enabled(true); -#endif - return true; - } - - case LFUN_CELL_SPLIT: - status.enabled(true); - return true; - - case LFUN_CELL_BACKWARD: - case LFUN_CELL_FORWARD: - status.enabled(true); - return true; - - default: - return InsetMathNest::getStatus(cur, cmd, status); - } -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathGrid.cpp b/src/mathed/InsetMathGrid.cpp new file mode 100644 index 0000000000..53354fa623 --- /dev/null +++ b/src/mathed/InsetMathGrid.cpp @@ -0,0 +1,1400 @@ +/** + * \file InsetMathGrid.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathGrid.h" +#include "MathData.h" +#include "MathParser.h" +#include "MathStream.h" + +#include "BufferView.h" +#include "CutAndPaste.h" +#include "FuncStatus.h" +#include "LColor.h" +#include "cursor.h" +#include "debug.h" +#include "funcrequest.h" +#include "gettext.h" +#include "undo.h" + +#include "frontends/Clipboard.h" +#include "frontends/Painter.h" + +#include "insets/MailInset.h" + +#include "support/lstrings.h" + +#include + + +namespace lyx { + +using support::bformat; + +using std::endl; +using std::max; +using std::min; +using std::swap; + +using std::string; +using std::auto_ptr; +using std::istream; +using std::istringstream; +using std::vector; + +class GridInsetMailer : public MailInset { +public: + GridInsetMailer(InsetMathGrid & inset) : inset_(inset) {} + /// + virtual string const & name() const + { + static string const theName = "tabular"; + return theName; + } + /// + virtual string const inset2string(Buffer const &) const + { + odocstringstream data; + //data << name() << " active_cell " << inset.getActCell() << '\n'; + data << from_utf8(name()) << " active_cell " << 0 << '\n'; + WriteStream ws(data); + inset_.write(ws); + return to_utf8(data.str()); + } + +protected: + InsetBase & inset() const { return inset_; } + InsetMathGrid & inset_; +}; + + +namespace { + +docstring verboseHLine(int n) +{ + docstring res; + for (int i = 0; i < n; ++i) + res += "\\hline"; + if (n) + res += ' '; + return res; +} + + +int extractInt(istream & is) +{ + int num = 1; + is >> num; + return (num == 0) ? 1 : num; +} + +} + + +////////////////////////////////////////////////////////////// + + +InsetMathGrid::CellInfo::CellInfo() + : dummy_(false) +{} + + + + +////////////////////////////////////////////////////////////// + + +InsetMathGrid::RowInfo::RowInfo() + : lines_(0), skip_(0), allow_pagebreak_(true) +{} + + + +int InsetMathGrid::RowInfo::skipPixels() const +{ + return crskip_.inBP(); +} + + + +////////////////////////////////////////////////////////////// + + +InsetMathGrid::ColInfo::ColInfo() + : align_('c'), lines_(0) +{} + + +////////////////////////////////////////////////////////////// + + +InsetMathGrid::InsetMathGrid(char v, docstring const & h) + : InsetMathNest(guessColumns(h)), + rowinfo_(2), + colinfo_(guessColumns(h) + 1), + cellinfo_(1 * guessColumns(h)) +{ + setDefaults(); + valign(v); + halign(h); + //lyxerr << "created grid with " << ncols() << " columns" << endl; +} + + +InsetMathGrid::InsetMathGrid() + : InsetMathNest(1), + rowinfo_(1 + 1), + colinfo_(1 + 1), + cellinfo_(1), + v_align_('c') +{ + setDefaults(); +} + + +InsetMathGrid::InsetMathGrid(col_type m, row_type n) + : InsetMathNest(m * n), + rowinfo_(n + 1), + colinfo_(m + 1), + cellinfo_(m * n), + v_align_('c') +{ + setDefaults(); +} + + +InsetMathGrid::InsetMathGrid(col_type m, row_type n, char v, docstring const & h) + : InsetMathNest(m * n), + rowinfo_(n + 1), + colinfo_(m + 1), + cellinfo_(m * n), + v_align_(v) +{ + setDefaults(); + valign(v); + halign(h); +} + + +auto_ptr InsetMathGrid::doClone() const +{ + return auto_ptr(new InsetMathGrid(*this)); +} + + +InsetMath::idx_type InsetMathGrid::index(row_type row, col_type col) const +{ + return col + ncols() * row; +} + + +void InsetMathGrid::setDefaults() +{ + if (ncols() <= 0) + lyxerr << "positive number of columns expected" << endl; + //if (nrows() <= 0) + // lyxerr << "positive number of rows expected" << endl; + for (col_type col = 0; col < ncols(); ++col) { + colinfo_[col].align_ = defaultColAlign(col); + colinfo_[col].skip_ = defaultColSpace(col); + } +} + + +void InsetMathGrid::halign(docstring const & hh) +{ + col_type col = 0; + for (docstring::const_iterator it = hh.begin(); it != hh.end(); ++it) { + char_type c = *it; + if (c == '|') { + colinfo_[col].lines_++; + } else if (col >= ncols()) { + // Only '|' is allowed in the last dummy column + break; + } else if (c == 'c' || c == 'l' || c == 'r') { + colinfo_[col].align_ = (char)c; + ++col; + colinfo_[col].lines_ = 0; + } else { + lyxerr << "unknown column separator: '" << c << "'" << endl; + } + } + +/* + col_type n = hh.size(); + if (n > ncols()) + n = ncols(); + for (col_type col = 0; col < n; ++col) + colinfo_[col].align_ = hh[col]; +*/ +} + + +InsetMathGrid::col_type InsetMathGrid::guessColumns(docstring const & hh) const +{ + col_type col = 0; + for (docstring::const_iterator it = hh.begin(); it != hh.end(); ++it) + if (*it == 'c' || *it == 'l' || *it == 'r') + ++col; + // let's have at least one column, even if we did not recognize its + // alignment + if (col == 0) + col = 1; + return col; +} + + +void InsetMathGrid::halign(char h, col_type col) +{ + colinfo_[col].align_ = h; +} + + +char InsetMathGrid::halign(col_type col) const +{ + return colinfo_[col].align_; +} + + +docstring InsetMathGrid::halign() const +{ + docstring res; + for (col_type col = 0; col < ncols(); ++col) { + res += docstring(colinfo_[col].lines_, '|'); + res += colinfo_[col].align_; + } + return res + docstring(colinfo_[ncols()].lines_, '|'); +} + + +void InsetMathGrid::valign(char c) +{ + v_align_ = c; +} + + +char InsetMathGrid::valign() const +{ + return v_align_; +} + + +InsetMathGrid::col_type InsetMathGrid::ncols() const +{ + return colinfo_.size() - 1; +} + + +InsetMathGrid::row_type InsetMathGrid::nrows() const +{ + return rowinfo_.size() - 1; +} + + +InsetMathGrid::col_type InsetMathGrid::col(idx_type idx) const +{ + return idx % ncols(); +} + + +InsetMathGrid::row_type InsetMathGrid::row(idx_type idx) const +{ + return idx / ncols(); +} + + +void InsetMathGrid::vcrskip(LyXLength const & crskip, row_type row) +{ + rowinfo_[row].crskip_ = crskip; +} + + +LyXLength InsetMathGrid::vcrskip(row_type row) const +{ + return rowinfo_[row].crskip_; +} + + +void InsetMathGrid::metrics(MetricsInfo & mi) const +{ + // let the cells adjust themselves + InsetMathNest::metrics(mi); + + // compute absolute sizes of vertical structure + for (row_type row = 0; row < nrows(); ++row) { + int asc = 0; + int desc = 0; + for (col_type col = 0; col < ncols(); ++col) { + MathArray const & c = cell(index(row, col)); + asc = max(asc, c.ascent()); + desc = max(desc, c.descent()); + } + rowinfo_[row].ascent_ = asc; + rowinfo_[row].descent_ = desc; + } + rowinfo_[0].ascent_ += hlinesep() * rowinfo_[0].lines_; + rowinfo_[nrows()].ascent_ = 0; + rowinfo_[nrows()].descent_ = 0; + + // compute vertical offsets + rowinfo_[0].offset_ = 0; + for (row_type row = 1; row <= nrows(); ++row) { + rowinfo_[row].offset_ = + rowinfo_[row - 1].offset_ + + rowinfo_[row - 1].descent_ + + rowinfo_[row - 1].skipPixels() + + rowsep() + + rowinfo_[row].lines_ * hlinesep() + + rowinfo_[row].ascent_; + } + + // adjust vertical offset + int h = 0; + switch (v_align_) { + case 't': + h = 0; + break; + case 'b': + h = rowinfo_[nrows() - 1].offset_; + break; + default: + h = rowinfo_[nrows() - 1].offset_ / 2; + } + for (row_type row = 0; row <= nrows(); ++row) + rowinfo_[row].offset_ -= h; + + + // compute absolute sizes of horizontal structure + for (col_type col = 0; col < ncols(); ++col) { + int wid = 0; + for (row_type row = 0; row < nrows(); ++row) + wid = max(wid, cell(index(row, col)).width()); + colinfo_[col].width_ = wid; + } + colinfo_[ncols()].width_ = 0; + + // compute horizontal offsets + colinfo_[0].offset_ = border(); + for (col_type col = 1; col <= ncols(); ++col) { + colinfo_[col].offset_ = + colinfo_[col - 1].offset_ + + colinfo_[col - 1].width_ + + colinfo_[col - 1].skip_ + + colsep() + + colinfo_[col].lines_ * vlinesep(); + } + + + dim_.wid = colinfo_[ncols() - 1].offset_ + + colinfo_[ncols() - 1].width_ + + vlinesep() * colinfo_[ncols()].lines_ + + border(); + + dim_.asc = - rowinfo_[0].offset_ + + rowinfo_[0].ascent_ + + hlinesep() * rowinfo_[0].lines_ + + border(); + + dim_.des = rowinfo_[nrows() - 1].offset_ + + rowinfo_[nrows() - 1].descent_ + + hlinesep() * rowinfo_[nrows()].lines_ + + border(); + + +/* + // Increase ws_[i] for 'R' columns (except the first one) + for (int i = 1; i < nc_; ++i) + if (align_[i] == 'R') + ws_[i] += 10 * df_width; + // Increase ws_[i] for 'C' column + if (align_[0] == 'C') + if (ws_[0] < 7 * workwidth / 8) + ws_[0] = 7 * workwidth / 8; + + // Adjust local tabs + width = colsep(); + for (cxrow = row_.begin(); cxrow; ++cxrow) { + int rg = COLSEP; + int lf = 0; + for (int i = 0; i < nc_; ++i) { + bool isvoid = false; + if (cxrow->getTab(i) <= 0) { + cxrow->setTab(i, df_width); + isvoid = true; + } + switch (align_[i]) { + case 'l': + lf = 0; + break; + case 'c': + lf = (ws_[i] - cxrow->getTab(i))/2; + break; + case 'r': + case 'R': + lf = ws_[i] - cxrow->getTab(i); + break; + case 'C': + if (cxrow == row_.begin()) + lf = 0; + else if (cxrow.is_last()) + lf = ws_[i] - cxrow->getTab(i); + else + lf = (ws_[i] - cxrow->getTab(i))/2; + break; + } + int const ww = (isvoid) ? lf : lf + cxrow->getTab(i); + cxrow->setTab(i, lf + rg); + rg = ws_[i] - ww + colsep(); + if (cxrow == row_.begin()) + width += ws_[i] + colsep(); + } + cxrow->setBaseline(cxrow->getBaseline() - ascent); + } +*/ + metricsMarkers2(dim_); +} + + +bool InsetMathGrid::metrics(MetricsInfo & mi, Dimension & dim) const +{ + dim = dim_; + metrics(mi); + if (dim_ == dim) + return false; + dim = dim_; + return true; +} + + +void InsetMathGrid::draw(PainterInfo & pi, int x, int y) const +{ + drawWithMargin(pi, x, y, 0, 0); +} + +void InsetMathGrid::drawWithMargin(PainterInfo & pi, int x, int y, + int lmargin, int rmargin) const +{ + for (idx_type idx = 0; idx < nargs(); ++idx) + cell(idx).draw(pi, x + lmargin + cellXOffset(idx), + y + cellYOffset(idx)); + + for (row_type row = 0; row <= nrows(); ++row) + for (unsigned int i = 0; i < rowinfo_[row].lines_; ++i) { + int yy = y + rowinfo_[row].offset_ - rowinfo_[row].ascent_ + - i * hlinesep() - hlinesep()/2 - rowsep()/2; + pi.pain.line(x + lmargin + 1, yy, + x + dim_.width() - rmargin - 1, yy, + LColor::foreground); + } + + for (col_type col = 0; col <= ncols(); ++col) + for (unsigned int i = 0; i < colinfo_[col].lines_; ++i) { + int xx = x + lmargin + colinfo_[col].offset_ + - i * vlinesep() - vlinesep()/2 - colsep()/2; + pi.pain.line(xx, y - dim_.ascent() + 1, + xx, y + dim_.descent() - 1, + LColor::foreground); + } + drawMarkers2(pi, x, y); +} + + +void InsetMathGrid::metricsT(TextMetricsInfo const & mi, Dimension & dim) const +{ + // let the cells adjust themselves + //InsetMathNest::metrics(mi); + for (idx_type i = 0; i < nargs(); ++i) + cell(i).metricsT(mi, dim); + + // compute absolute sizes of vertical structure + for (row_type row = 0; row < nrows(); ++row) { + int asc = 0; + int desc = 0; + for (col_type col = 0; col < ncols(); ++col) { + MathArray const & c = cell(index(row, col)); + asc = max(asc, c.ascent()); + desc = max(desc, c.descent()); + } + rowinfo_[row].ascent_ = asc; + rowinfo_[row].descent_ = desc; + } + //rowinfo_[0].ascent_ += hlinesep() * rowinfo_[0].lines_; + rowinfo_[nrows()].ascent_ = 0; + rowinfo_[nrows()].descent_ = 0; + + // compute vertical offsets + rowinfo_[0].offset_ = 0; + for (row_type row = 1; row <= nrows(); ++row) { + rowinfo_[row].offset_ = + rowinfo_[row - 1].offset_ + + rowinfo_[row - 1].descent_ + + //rowinfo_[row - 1].skipPixels() + + 1 + //rowsep() + + //rowinfo_[row].lines_ * hlinesep() + + rowinfo_[row].ascent_; + } + + // adjust vertical offset + int h = 0; + switch (v_align_) { + case 't': + h = 0; + break; + case 'b': + h = rowinfo_[nrows() - 1].offset_; + break; + default: + h = rowinfo_[nrows() - 1].offset_ / 2; + } + for (row_type row = 0; row <= nrows(); ++row) + rowinfo_[row].offset_ -= h; + + + // compute absolute sizes of horizontal structure + for (col_type col = 0; col < ncols(); ++col) { + int wid = 0; + for (row_type row = 0; row < nrows(); ++row) + wid = max(wid, cell(index(row, col)).width()); + colinfo_[col].width_ = wid; + } + colinfo_[ncols()].width_ = 0; + + // compute horizontal offsets + colinfo_[0].offset_ = border(); + for (col_type col = 1; col <= ncols(); ++col) { + colinfo_[col].offset_ = + colinfo_[col - 1].offset_ + + colinfo_[col - 1].width_ + + colinfo_[col - 1].skip_ + + 1 ; //colsep() + + //colinfo_[col].lines_ * vlinesep(); + } + + + dim.wid = colinfo_[ncols() - 1].offset_ + + colinfo_[ncols() - 1].width_ + //+ vlinesep() * colinfo_[ncols()].lines_ + + 2; + + dim.asc = -rowinfo_[0].offset_ + + rowinfo_[0].ascent_ + //+ hlinesep() * rowinfo_[0].lines_ + + 1; + + dim.des = rowinfo_[nrows() - 1].offset_ + + rowinfo_[nrows() - 1].descent_ + //+ hlinesep() * rowinfo_[nrows()].lines_ + + 1; +} + + +void InsetMathGrid::drawT(TextPainter & pain, int x, int y) const +{ + for (idx_type idx = 0; idx < nargs(); ++idx) + cell(idx).drawT(pain, x + cellXOffset(idx), y + cellYOffset(idx)); +} + + +docstring InsetMathGrid::eolString(row_type row, bool emptyline, bool fragile) const +{ + docstring eol; + + if (!rowinfo_[row].crskip_.zero()) + eol += '[' + from_utf8(rowinfo_[row].crskip_.asLatexString()) + ']'; + else if(!rowinfo_[row].allow_pagebreak_) + eol += '*'; + + // make sure an upcoming '[' does not break anything + if (row + 1 < nrows()) { + MathArray const & c = cell(index(row + 1, 0)); + if (c.size() && c.front()->getChar() == '[') + //eol += "[0pt]"; + eol += "{}"; + } + + // only add \\ if necessary + if (eol.empty() && row + 1 == nrows() && (nrows() == 1 || !emptyline)) + return docstring(); + + return (fragile ? "\\protect\\\\" : "\\\\") + eol; +} + + +docstring InsetMathGrid::eocString(col_type col, col_type lastcol) const +{ + if (col + 1 == lastcol) + return docstring(); + return from_ascii(" & "); +} + + +void InsetMathGrid::addRow(row_type row) +{ + rowinfo_.insert(rowinfo_.begin() + row + 1, RowInfo()); + cells_.insert + (cells_.begin() + (row + 1) * ncols(), ncols(), MathArray()); + cellinfo_.insert + (cellinfo_.begin() + (row + 1) * ncols(), ncols(), CellInfo()); +} + + +void InsetMathGrid::appendRow() +{ + rowinfo_.push_back(RowInfo()); + //cells_.insert(cells_.end(), ncols(), MathArray()); + for (col_type col = 0; col < ncols(); ++col) { + cells_.push_back(cells_type::value_type()); + cellinfo_.push_back(CellInfo()); + } +} + + +void InsetMathGrid::delRow(row_type row) +{ + if (nrows() == 1) + return; + + cells_type::iterator it = cells_.begin() + row * ncols(); + cells_.erase(it, it + ncols()); + + vector::iterator jt = cellinfo_.begin() + row * ncols(); + cellinfo_.erase(jt, jt + ncols()); + + rowinfo_.erase(rowinfo_.begin() + row); +} + + +void InsetMathGrid::copyRow(row_type row) +{ + addRow(row); + for (col_type col = 0; col < ncols(); ++col) + cells_[(row + 1) * ncols() + col] = cells_[row * ncols() + col]; +} + + +void InsetMathGrid::swapRow(row_type row) +{ + if (nrows() == 1) + return; + if (row + 1 == nrows()) + --row; + for (col_type col = 0; col < ncols(); ++col) + swap(cells_[row * ncols() + col], cells_[(row + 1) * ncols() + col]); +} + + +void InsetMathGrid::addCol(col_type newcol) +{ + const col_type nc = ncols(); + const row_type nr = nrows(); + cells_type new_cells((nc + 1) * nr); + vector new_cellinfo((nc + 1) * nr); + + for (row_type row = 0; row < nr; ++row) + for (col_type col = 0; col < nc; ++col) { + new_cells[row * (nc + 1) + col + (col > newcol)] + = cells_[row * nc + col]; + new_cellinfo[row * (nc + 1) + col + (col > newcol)] + = cellinfo_[row * nc + col]; + } + swap(cells_, new_cells); + swap(cellinfo_, new_cellinfo); + + ColInfo inf; + inf.skip_ = defaultColSpace(newcol); + inf.align_ = defaultColAlign(newcol); + colinfo_.insert(colinfo_.begin() + newcol, inf); +} + + +void InsetMathGrid::delCol(col_type col) +{ + if (ncols() == 1) + return; + + cells_type tmpcells; + vector tmpcellinfo; + for (col_type i = 0; i < nargs(); ++i) + if (i % ncols() != col) { + tmpcells.push_back(cells_[i]); + tmpcellinfo.push_back(cellinfo_[i]); + } + swap(cells_, tmpcells); + swap(cellinfo_, tmpcellinfo); + + colinfo_.erase(colinfo_.begin() + col); +} + + +void InsetMathGrid::copyCol(col_type col) +{ + addCol(col); + for (row_type row = 0; row < nrows(); ++row) + cells_[row * ncols() + col + 1] = cells_[row * ncols() + col]; +} + + +void InsetMathGrid::swapCol(col_type col) +{ + if (ncols() == 1) + return; + if (col + 1 == ncols()) + --col; + for (row_type row = 0; row < nrows(); ++row) + swap(cells_[row * ncols() + col], cells_[row * ncols() + col + 1]); +} + + +int InsetMathGrid::cellXOffset(idx_type idx) const +{ + col_type c = col(idx); + int x = colinfo_[c].offset_; + char align = colinfo_[c].align_; + if (align == 'r' || align == 'R') + x += colinfo_[c].width_ - cell(idx).width(); + if (align == 'c' || align == 'C') + x += (colinfo_[c].width_ - cell(idx).width()) / 2; + return x; +} + + +int InsetMathGrid::cellYOffset(idx_type idx) const +{ + return rowinfo_[row(idx)].offset_; +} + + +bool InsetMathGrid::idxUpDown(LCursor & cur, bool up) const +{ + if (up) { + if (cur.row() == 0) + return false; + cur.idx() -= ncols(); + } else { + if (cur.row() + 1 >= nrows()) + return false; + cur.idx() += ncols(); + } + cur.pos() = cur.cell().x2pos(cur.x_target() - cur.cell().xo(cur.bv())); + return true; +} + + +bool InsetMathGrid::idxLeft(LCursor & cur) const +{ + // leave matrix if on the left hand edge + if (cur.col() == 0) + return false; + --cur.idx(); + cur.pos() = cur.lastpos(); + return true; +} + + +bool InsetMathGrid::idxRight(LCursor & cur) const +{ + // leave matrix if on the right hand edge + if (cur.col() + 1 == ncols()) + return false; + ++cur.idx(); + cur.pos() = 0; + return true; +} + + +bool InsetMathGrid::idxFirst(LCursor & cur) const +{ + switch (v_align_) { + case 't': + cur.idx() = 0; + break; + case 'b': + cur.idx() = (nrows() - 1) * ncols(); + break; + default: + cur.idx() = ((nrows() - 1) / 2) * ncols(); + } + cur.pos() = 0; + return true; +} + + +bool InsetMathGrid::idxLast(LCursor & cur) const +{ + switch (v_align_) { + case 't': + cur.idx() = ncols() - 1; + break; + case 'b': + cur.idx() = nargs() - 1; + break; + default: + cur.idx() = ((nrows() - 1) / 2 + 1) * ncols() - 1; + } + cur.pos() = cur.lastpos(); + return true; +} + + +bool InsetMathGrid::idxDelete(idx_type & idx) +{ + // nothing to do if we have just one row + if (nrows() == 1) + return false; + + // nothing to do if we are in the middle of the last row of the inset + if (idx + ncols() > nargs()) + return false; + + // try to delete entire sequence of ncols() empty cells if possible + for (idx_type i = idx; i < idx + ncols(); ++i) + if (cell(i).size()) + return false; + + // move cells if necessary + for (idx_type i = index(row(idx), 0); i < idx; ++i) + swap(cell(i), cell(i + ncols())); + + delRow(row(idx)); + + if (idx >= nargs()) + idx = nargs() - 1; + + // undo effect of Ctrl-Tab (i.e. pull next cell) + //if (idx + 1 != nargs()) + // cell(idx).swap(cell(idx + 1)); + + // we handled the event.. + return true; +} + + +// reimplement old behaviour when pressing Delete in the last position +// of a cell +void InsetMathGrid::idxGlue(idx_type idx) +{ + col_type c = col(idx); + if (c + 1 == ncols()) { + if (row(idx) + 1 != nrows()) { + for (col_type cc = 0; cc < ncols(); ++cc) + cell(idx).append(cell(idx + cc + 1)); + delRow(row(idx) + 1); + } + } else { + cell(idx).append(cell(idx + 1)); + for (col_type cc = c + 2; cc < ncols(); ++cc) + cell(idx - c + cc - 1) = cell(idx - c + cc); + cell(idx - c + ncols() - 1).clear(); + } +} + + +InsetMathGrid::RowInfo const & InsetMathGrid::rowinfo(row_type row) const +{ + return rowinfo_[row]; +} + + +InsetMathGrid::RowInfo & InsetMathGrid::rowinfo(row_type row) +{ + return rowinfo_[row]; +} + + +bool InsetMathGrid::idxBetween(idx_type idx, idx_type from, idx_type to) const +{ + row_type const ri = row(idx); + row_type const r1 = min(row(from), row(to)); + row_type const r2 = max(row(from), row(to)); + col_type const ci = col(idx); + col_type const c1 = min(col(from), col(to)); + col_type const c2 = max(col(from), col(to)); + return r1 <= ri && ri <= r2 && c1 <= ci && ci <= c2; +} + + + +void InsetMathGrid::normalize(NormalStream & os) const +{ + os << "[grid "; + for (row_type row = 0; row < nrows(); ++row) { + os << "[row "; + for (col_type col = 0; col < ncols(); ++col) + os << "[cell " << cell(index(row, col)) << ']'; + os << ']'; + } + os << ']'; +} + + +void InsetMathGrid::mathmlize(MathStream & os) const +{ + os << MTag("mtable"); + for (row_type row = 0; row < nrows(); ++row) { + os << MTag("mtr"); + for (col_type col = 0; col < ncols(); ++col) + os << cell(index(row, col)); + os << ETag("mtr"); + } + os << ETag("mtable"); +} + + +void InsetMathGrid::write(WriteStream & os) const +{ + docstring eol; + for (row_type row = 0; row < nrows(); ++row) { + os << verboseHLine(rowinfo_[row].lines_); + // don't write & and empty cells at end of line + col_type lastcol = 0; + bool emptyline = true; + for (col_type col = 0; col < ncols(); ++col) + if (!cell(index(row, col)).empty()) { + lastcol = col + 1; + emptyline = false; + } + for (col_type col = 0; col < lastcol; ++col) + os << cell(index(row, col)) << eocString(col, lastcol); + eol = eolString(row, emptyline, os.fragile()); + os << eol; + // append newline only if line wasn't completely empty + // and this was not the last line in the grid + if (!emptyline && row + 1 < nrows()) + os << "\n"; + } + docstring const s = verboseHLine(rowinfo_[nrows()].lines_); + if (!s.empty()) { + if (eol.empty()) { + if (os.fragile()) + os << "\\protect"; + os << "\\\\"; + } + os << s; + } +} + + +int InsetMathGrid::colsep() const +{ + return 6; +} + + +int InsetMathGrid::rowsep() const +{ + return 6; +} + + +int InsetMathGrid::hlinesep() const +{ + return 3; +} + + +int InsetMathGrid::vlinesep() const +{ + return 3; +} + + +int InsetMathGrid::border() const +{ + return 1; +} + + +void InsetMathGrid::splitCell(LCursor & cur) +{ + if (cur.idx() == cur.lastidx()) + return; + MathArray ar = cur.cell(); + ar.erase(0, cur.pos()); + cur.cell().erase(cur.pos(), cur.lastpos()); + ++cur.idx(); + cur.pos() = 0; + cur.cell().insert(0, ar); +} + + +void InsetMathGrid::doDispatch(LCursor & cur, FuncRequest & cmd) +{ + //lyxerr << "*** InsetMathGrid: request: " << cmd << endl; + switch (cmd.action) { + + case LFUN_MOUSE_RELEASE: + //if (cmd.button() == mouse_button::button3) { + // GridInsetMailer(*this).showDialog(); + // return DispatchResult(true, true); + //} + InsetMathNest::doDispatch(cur, cmd); + break; + + case LFUN_INSET_DIALOG_UPDATE: + GridInsetMailer(*this).updateDialog(&cur.bv()); + break; + + // insert file functions + case LFUN_LINE_DELETE: + // FIXME: We use recordUndoInset when a change reflects more + // than one cell, because recordUndo does not work for + // multiple cells. Unfortunately this puts the cursor in front + // of the inset after undo. This is (especilally for large + // grids) annoying. + recordUndoInset(cur); + //autocorrect_ = false; + //macroModeClose(); + //if (selection_) { + // selDel(); + // break; + //} + if (nrows() > 1) + delRow(cur.row()); + if (cur.idx() > cur.lastidx()) + cur.idx() = cur.lastidx(); + if (cur.pos() > cur.lastpos()) + cur.pos() = cur.lastpos(); + break; + + case LFUN_CELL_SPLIT: + recordUndo(cur); + splitCell(cur); + break; + + case LFUN_CELL_BACKWARD: + // See below. + cur.selection() = false; + if (!idxPrev(cur)) { + cmd = FuncRequest(LFUN_FINISHED_LEFT); + cur.undispatched(); + } + break; + + case LFUN_CELL_FORWARD: + // Can't handle selection by additional 'shift' as this is + // hard bound to LFUN_CELL_BACKWARD + cur.selection() = false; + if (!idxNext(cur)) { + cmd = FuncRequest(LFUN_FINISHED_RIGHT); + cur.undispatched(); + } + break; + + case LFUN_BREAK_LINE: { + recordUndoInset(cur); + row_type const r = cur.row(); + addRow(r); + + // split line + for (col_type c = col(cur.idx()) + 1; c < ncols(); ++c) + swap(cell(index(r, c)), cell(index(r + 1, c))); + + // split cell + splitCell(cur); + swap(cell(cur.idx()), cell(cur.idx() + ncols() - 1)); + if (cur.idx() > 0) + --cur.idx(); + cur.pos() = cur.lastpos(); + + //mathcursor->normalize(); + //cmd = FuncRequest(LFUN_FINISHED_LEFT); + break; + } + + case LFUN_TABULAR_FEATURE: { + recordUndoInset(cur); + //lyxerr << "handling tabular-feature " << to_utf8(cmd.argument()) << endl; + istringstream is(to_utf8(cmd.argument())); + string s; + is >> s; + if (s == "valign-top") + valign('t'); + else if (s == "valign-middle") + valign('c'); + else if (s == "valign-bottom") + valign('b'); + else if (s == "align-left") + halign('l', cur.col()); + else if (s == "align-right") + halign('r', cur.col()); + else if (s == "align-center") + halign('c', cur.col()); + else if (s == "append-row") + for (int i = 0, n = extractInt(is); i < n; ++i) + addRow(cur.row()); + else if (s == "delete-row") { + for (int i = 0, n = extractInt(is); i < n; ++i) { + delRow(cur.row()); + if (cur.idx() >= nargs()) + cur.idx() -= ncols(); + } + cur.pos() = 0; // trick, see below + } + else if (s == "copy-row") { + // Here (as later) we save the cursor col/row + // in order to restore it after operation. + row_type const r = cur.row(); + col_type const c = cur.col(); + for (int i = 0, n = extractInt(is); i < n; ++i) + copyRow(cur.row()); + cur.idx() = index(r, c); + } + else if (s == "swap-row") { + swapRow(cur.row()); + // Trick to suppress same-idx-means-different-cell + // assertion crash: + cur.pos() = 0; + } + else if (s == "add-hline-above") + rowinfo_[cur.row()].lines_++; + else if (s == "add-hline-below") + rowinfo_[cur.row()+1].lines_++; + else if (s == "delete-hline-above") + rowinfo_[cur.row()].lines_--; + else if (s == "delete-hline-below") + rowinfo_[cur.row()+1].lines_--; + else if (s == "append-column") { + row_type const r = cur.row(); + col_type const c = cur.col(); + for (int i = 0, n = extractInt(is); i < n; ++i) + addCol(cur.col()); + cur.idx() = index(r, c); + } + else if (s == "delete-column") { + row_type const r = cur.row(); + col_type const c = cur.col(); + for (int i = 0, n = extractInt(is); i < n; ++i) + delCol(col(cur.idx())); + cur.idx() = index(r, min(c, cur.ncols() - 1)); + cur.pos() = 0; // trick, see above + } + else if (s == "copy-column") { + row_type const r = cur.row(); + col_type const c = cur.col(); + copyCol(cur.col()); + cur.idx() = index(r, c); + } + else if (s == "swap-column") { + swapCol(cur.col()); + cur.pos() = 0; // trick, see above + } + else if (s == "add-vline-left") + colinfo_[cur.col()].lines_++; + else if (s == "add-vline-right") + colinfo_[cur.col()+1].lines_++; + else if (s == "delete-vline-left") + colinfo_[cur.col()].lines_--; + else if (s == "delete-vline-right") + colinfo_[cur.col()+1].lines_--; + else { + cur.undispatched(); + break; + } + lyxerr << "returning FINISHED_LEFT" << endl; + break; + } + + case LFUN_PASTE: { + cur.message(_("Paste")); + cap::replaceSelection(cur); + docstring topaste; + if (cmd.argument().empty() && !theClipboard().isInternal()) + topaste = theClipboard().getAsText(); + else { + idocstringstream is(cmd.argument()); + int n = 0; + is >> n; + topaste = cap::getSelection(cur.buffer(), n); + } + InsetMathGrid grid(1, 1); + if (!topaste.empty()) + mathed_parse_normal(grid, topaste); + + if (grid.nargs() == 1) { + // single cell/part of cell + recordUndo(cur); + cur.cell().insert(cur.pos(), grid.cell(0)); + cur.pos() += grid.cell(0).size(); + } else { + // multiple cells + recordUndoInset(cur); + col_type const numcols = + min(grid.ncols(), ncols() - col(cur.idx())); + row_type const numrows = + min(grid.nrows(), nrows() - cur.row()); + for (row_type r = 0; r < numrows; ++r) { + for (col_type c = 0; c < numcols; ++c) { + idx_type i = index(r + cur.row(), c + col(cur.idx())); + cell(i).insert(0, grid.cell(grid.index(r, c))); + } + // append the left over horizontal cells to the last column + idx_type i = index(r + cur.row(), ncols() - 1); + for (InsetMath::col_type c = numcols; c < grid.ncols(); ++c) + cell(i).append(grid.cell(grid.index(r, c))); + } + // append the left over vertical cells to the last _cell_ + idx_type i = nargs() - 1; + for (row_type r = numrows; r < grid.nrows(); ++r) + for (col_type c = 0; c < grid.ncols(); ++c) + cell(i).append(grid.cell(grid.index(r, c))); + } + cur.clearSelection(); // bug 393 + cur.bv().switchKeyMap(); + finishUndo(); + break; + } + + case LFUN_LINE_BEGIN_SELECT: + case LFUN_LINE_BEGIN: + case LFUN_WORD_BACKWARD_SELECT: + case LFUN_WORD_BACKWARD: + cur.selHandle(cmd.action == LFUN_WORD_BACKWARD_SELECT || + cmd.action == LFUN_LINE_BEGIN_SELECT); + cur.macroModeClose(); + if (cur.pos() != 0) { + cur.pos() = 0; + } else if (cur.idx() % cur.ncols() != 0) { + cur.idx() -= cur.idx() % cur.ncols(); + cur.pos() = 0; + } else if (cur.idx() != 0) { + cur.idx() = 0; + cur.pos() = 0; + } else { + cmd = FuncRequest(LFUN_FINISHED_LEFT); + cur.undispatched(); + } + break; + + case LFUN_WORD_FORWARD_SELECT: + case LFUN_WORD_FORWARD: + case LFUN_LINE_END_SELECT: + case LFUN_LINE_END: + cur.selHandle(cmd.action == LFUN_WORD_FORWARD_SELECT || + cmd.action == LFUN_LINE_END_SELECT); + cur.macroModeClose(); + cur.clearTargetX(); + if (cur.pos() != cur.lastpos()) { + cur.pos() = cur.lastpos(); + } else if ((cur.idx() + 1) % cur.ncols() != 0) { + cur.idx() += cur.ncols() - 1 - cur.idx() % cur.ncols(); + cur.pos() = cur.lastpos(); + } else if (cur.idx() != cur.lastidx()) { + cur.idx() = cur.lastidx(); + cur.pos() = cur.lastpos(); + } else { + cmd = FuncRequest(LFUN_FINISHED_RIGHT); + cur.undispatched(); + } + break; + + default: + InsetMathNest::doDispatch(cur, cmd); + } +} + + +bool InsetMathGrid::getStatus(LCursor & cur, FuncRequest const & cmd, + FuncStatus & status) const +{ + switch (cmd.action) { + case LFUN_TABULAR_FEATURE: { + string const s = to_utf8(cmd.argument()); + if (nrows() <= 1 && (s == "delete-row" || s == "swap-row")) { + status.enabled(false); + status.message(from_utf8(N_("Only one row"))); + return true; + } + if (ncols() <= 1 && + (s == "delete-column" || s == "swap-column")) { + status.enabled(false); + status.message(from_utf8(N_("Only one column"))); + return true; + } + if ((rowinfo_[cur.row()].lines_ == 0 && + s == "delete-hline-above") || + (rowinfo_[cur.row() + 1].lines_ == 0 && + s == "delete-hline-below")) { + status.enabled(false); + status.message(from_utf8(N_("No hline to delete"))); + return true; + } + + if ((colinfo_[cur.col()].lines_ == 0 && + s == "delete-vline-left") || + (colinfo_[cur.col() + 1].lines_ == 0 && + s == "delete-vline-right")) { + status.enabled(false); + status.message(from_utf8(N_("No vline to delete"))); + return true; + } + if (s == "valign-top" || s == "valign-middle" || + s == "valign-bottom" || s == "align-left" || + s == "align-right" || s == "align-center" || + s == "append-row" || s == "delete-row" || + s == "copy-row" || s == "swap-row" || + s == "add-hline-above" || s == "add-hline-below" || + s == "delete-hline-above" || s == "delete-hline-below" || + s == "append-column" || s == "delete-column" || + s == "copy-column" || s == "swap-column" || + s == "add-vline-left" || s == "add-vline-right" || + s == "delete-vline-left" || s == "delete-vline-right") + status.enabled(true); + else { + status.enabled(false); + status.message(bformat( + from_utf8(N_("Unknown tabular feature '%1$s'")), lyx::from_ascii(s))); + } + + status.setOnOff(s == "align-left" && halign(cur.col()) == 'l' + || s == "align-right" && halign(cur.col()) == 'r' + || s == "align-center" && halign(cur.col()) == 'c' + || s == "valign-top" && valign() == 't' + || s == "valign-bottom" && valign() == 'b' + || s == "valign-middle" && valign() == 'm'); + +#if 0 + // FIXME: What did this code do? + // Please check whether it is still needed! + // should be more precise + if (v_align_ == '\0') { + status.enable(true); + break; + } + if (cmd.argument().empty()) { + status.enable(false); + break; + } + if (!support::contains("tcb", cmd.argument()[0])) { + status.enable(false); + break; + } + status.setOnOff(cmd.argument()[0] == v_align_); + status.enabled(true); +#endif + return true; + } + + case LFUN_CELL_SPLIT: + status.enabled(true); + return true; + + case LFUN_CELL_BACKWARD: + case LFUN_CELL_FORWARD: + status.enabled(true); + return true; + + default: + return InsetMathNest::getStatus(cur, cmd, status); + } +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathHull.C b/src/mathed/InsetMathHull.C deleted file mode 100644 index cd3a59081b..0000000000 --- a/src/mathed/InsetMathHull.C +++ /dev/null @@ -1,1525 +0,0 @@ -/** - * \file InsetMathHull.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathArray.h" -#include "InsetMathChar.h" -#include "InsetMathColor.h" -#include "MathData.h" -#include "InsetMathDelim.h" -#include "MathExtern.h" -#include "MathFactory.h" -#include "InsetMathHull.h" -#include "MathStream.h" -#include "MathParser.h" -#include "InsetMathSpace.h" -#include "MathStream.h" -#include "MathSupport.h" -#include "InsetMathRef.h" - -#include "bufferview_funcs.h" -#include "lyxtext.h" - -#include "buffer.h" -#include "bufferparams.h" -#include "BufferView.h" -#include "CutAndPaste.h" -#include "FuncStatus.h" -#include "LColor.h" -#include "LaTeXFeatures.h" -#include "cursor.h" -#include "debug.h" -#include "dispatchresult.h" -#include "funcrequest.h" -#include "gettext.h" -#include "lyxrc.h" -#include "outputparams.h" -#include "sgml.h" -#include "TextPainter.h" -#include "undo.h" - -#include "insets/RenderPreview.h" -#include "insets/InsetLabel.h" - -#include "graphics/PreviewImage.h" -#include "graphics/PreviewLoader.h" - -#include "support/lyxlib.h" -#include "support/lstrings.h" - -#include - -#include - - -namespace lyx { - -using cap::grabAndEraseSelection; -using support::bformat; -using support::subst; - -using std::endl; -using std::max; -using std::ostream; -using std::auto_ptr; -using std::istringstream; -using std::ostringstream; -using std::pair; -using std::swap; -using std::vector; - - -namespace { - - int getCols(HullType type) - { - switch (type) { - case hullEqnArray: - return 3; - case hullAlign: - case hullFlAlign: - case hullAlignAt: - case hullXAlignAt: - case hullXXAlignAt: - return 2; - default: - return 1; - } - } - - - // returns position of first relation operator in the array - // used for "intelligent splitting" - size_t firstRelOp(MathArray const & ar) - { - for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) - if ((*it)->isRelOp()) - return it - ar.begin(); - return ar.size(); - } - - - char const * star(bool numbered) - { - return numbered ? "" : "*"; - } - - -} // end anon namespace - - -HullType hullType(docstring const & s) -{ - if (s == "none") return hullNone; - if (s == "simple") return hullSimple; - if (s == "equation") return hullEquation; - if (s == "eqnarray") return hullEqnArray; - if (s == "align") return hullAlign; - if (s == "alignat") return hullAlignAt; - if (s == "xalignat") return hullXAlignAt; - if (s == "xxalignat") return hullXXAlignAt; - if (s == "multline") return hullMultline; - if (s == "gather") return hullGather; - if (s == "flalign") return hullFlAlign; - lyxerr << "unknown hull type '" << to_utf8(s) << "'" << endl; - return HullType(-1); -} - - -docstring hullName(HullType type) -{ - switch (type) { - case hullNone: return from_ascii("none"); - case hullSimple: return from_ascii("simple"); - case hullEquation: return from_ascii("equation"); - case hullEqnArray: return from_ascii("eqnarray"); - case hullAlign: return from_ascii("align"); - case hullAlignAt: return from_ascii("alignat"); - case hullXAlignAt: return from_ascii("xalignat"); - case hullXXAlignAt: return from_ascii("xxalignat"); - case hullMultline: return from_ascii("multline"); - case hullGather: return from_ascii("gather"); - case hullFlAlign: return from_ascii("flalign"); - default: - lyxerr << "unknown hull type '" << type << "'" << endl; - return from_ascii("none"); - } -} - - -InsetMathHull::InsetMathHull() - : InsetMathGrid(1, 1), type_(hullNone), nonum_(1), label_(1), - preview_(new RenderPreview(this)) -{ - //lyxerr << "sizeof InsetMath: " << sizeof(InsetMath) << endl; - //lyxerr << "sizeof MetricsInfo: " << sizeof(MetricsInfo) << endl; - //lyxerr << "sizeof InsetMathChar: " << sizeof(InsetMathChar) << endl; - //lyxerr << "sizeof LyXFont: " << sizeof(LyXFont) << endl; - initMath(); - setDefaults(); -} - - -InsetMathHull::InsetMathHull(HullType type) - : InsetMathGrid(getCols(type), 1), type_(type), nonum_(1), label_(1), - preview_(new RenderPreview(this)) -{ - initMath(); - setDefaults(); -} - - -InsetMathHull::InsetMathHull(InsetMathHull const & other) - : InsetMathGrid(other), - type_(other.type_), nonum_(other.nonum_), label_(other.label_), - preview_(new RenderPreview(this)) -{} - - -InsetMathHull::~InsetMathHull() -{} - - -auto_ptr InsetMathHull::doClone() const -{ - return auto_ptr(new InsetMathHull(*this)); -} - - -InsetMathHull & InsetMathHull::operator=(InsetMathHull const & other) -{ - if (this == &other) - return *this; - *static_cast(this) = InsetMathGrid(other); - type_ = other.type_; - nonum_ = other.nonum_; - label_ = other.label_; - preview_.reset(new RenderPreview(*other.preview_, this)); - - return *this; -} - - -InsetBase * InsetMathHull::editXY(LCursor & cur, int x, int y) -{ - if (use_preview_) { - edit(cur, true); - return this; - } - return InsetMathNest::editXY(cur, x, y); -} - - -InsetMath::mode_type InsetMathHull::currentMode() const -{ - if (type_ == hullNone) - return UNDECIDED_MODE; - // definitely math mode ... - return MATH_MODE; -} - - -bool InsetMathHull::idxFirst(LCursor & cur) const -{ - cur.idx() = 0; - cur.pos() = 0; - return true; -} - - -bool InsetMathHull::idxLast(LCursor & cur) const -{ - cur.idx() = nargs() - 1; - cur.pos() = cur.lastpos(); - return true; -} - - -char InsetMathHull::defaultColAlign(col_type col) -{ - if (type_ == hullEqnArray) - return "rcl"[col]; - if (type_ >= hullAlign) - return "rl"[col & 1]; - return 'c'; -} - - -int InsetMathHull::defaultColSpace(col_type col) -{ - if (type_ == hullAlign || type_ == hullAlignAt) - return 0; - if (type_ == hullXAlignAt) - return (col & 1) ? 20 : 0; - if (type_ == hullXXAlignAt || type_ == hullFlAlign) - return (col & 1) ? 40 : 0; - return 0; -} - - -docstring InsetMathHull::standardFont() const -{ - return from_ascii(type_ == hullNone ? "lyxnochange" : "mathnormal"); -} - - -bool InsetMathHull::previewState(BufferView * bv) const -{ - if (!editing(bv) && RenderPreview::status() == LyXRC::PREVIEW_ON) { - graphics::PreviewImage const * pimage = - preview_->getPreviewImage(*bv->buffer()); - return pimage && pimage->image(); - } - return false; -} - - -bool InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const -{ - if (previewState(mi.base.bv)) { - preview_->metrics(mi, dim); - // insert a one pixel gap in front of the formula - dim.wid += 1; - if (display()) - dim.des += displayMargin(); - if (dim_ == dim) - return false; - dim_ = dim; - return true; - } - - FontSetChanger dummy1(mi.base, standardFont()); - StyleChanger dummy2(mi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT); - - // let the cells adjust themselves - InsetMathGrid::metrics(mi, dim); - - if (display()) { - dim.asc += displayMargin(); - dim.des += displayMargin(); - } - - if (numberedType()) { - FontSetChanger dummy(mi.base, from_ascii("mathbf")); - int l = 0; - for (row_type row = 0; row < nrows(); ++row) - l = max(l, mathed_string_width(mi.base.font, nicelabel(row))); - - if (l) - dim.wid += 30 + l; - } - - // make it at least as high as the current font - int asc = 0; - int des = 0; - math_font_max_dim(mi.base.font, asc, des); - dim.asc = max(dim.asc, asc); - dim.des = max(dim.des, des); - - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathHull::draw(PainterInfo & pi, int x, int y) const -{ - use_preview_ = previewState(pi.base.bv); - - if (use_preview_) { - // one pixel gap in front - preview_->draw(pi, x + 1, y); - setPosCache(pi, x, y); - return; - } - - FontSetChanger dummy1(pi.base, standardFont()); - StyleChanger dummy2(pi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT); - InsetMathGrid::draw(pi, x + 1, y); - - if (numberedType()) { - int const xx = x + colinfo_.back().offset_ + colinfo_.back().width_ + 20; - for (row_type row = 0; row < nrows(); ++row) { - int const yy = y + rowinfo_[row].offset_; - FontSetChanger dummy(pi.base, from_ascii("mathrm")); - docstring const nl = nicelabel(row); - pi.draw(xx, yy, nl); - } - } - setPosCache(pi, x, y); -} - - -void InsetMathHull::metricsT(TextMetricsInfo const & mi, Dimension & dim) const -{ - if (display()) { - InsetMathGrid::metricsT(mi, dim); - } else { - odocstringstream os; - WriteStream wi(os, false, true); - write(wi); - dim.wid = os.str().size(); - dim.asc = 1; - dim.des = 0; - } -} - - -void InsetMathHull::drawT(TextPainter & pain, int x, int y) const -{ - if (display()) { - InsetMathGrid::drawT(pain, x, y); - } else { - odocstringstream os; - WriteStream wi(os, false, true); - write(wi); - pain.draw(x, y, os.str().c_str()); - } -} - - -namespace { - -docstring const latex_string(InsetMathHull const & inset) -{ - odocstringstream ls; - WriteStream wi(ls, false, false); - inset.write(wi); - return ls.str(); -} - -} // namespace anon - - -void InsetMathHull::addPreview(graphics::PreviewLoader & ploader) const -{ - if (RenderPreview::status() == LyXRC::PREVIEW_ON) { - docstring const snippet = latex_string(*this); - preview_->addPreview(snippet, ploader); - } -} - - -bool InsetMathHull::notifyCursorLeaves(LCursor & cur) -{ - if (RenderPreview::status() == LyXRC::PREVIEW_ON) { - Buffer const & buffer = cur.buffer(); - docstring const snippet = latex_string(*this); - preview_->addPreview(snippet, buffer); - preview_->startLoading(buffer); - cur.updateFlags(Update::Force); - } - return false; -} - - -docstring InsetMathHull::label(row_type row) const -{ - BOOST_ASSERT(row < nrows()); - return label_[row]; -} - - -void InsetMathHull::label(row_type row, docstring const & label) -{ - //lyxerr << "setting label '" << label << "' for row " << row << endl; - label_[row] = label; -} - - -void InsetMathHull::numbered(row_type row, bool num) -{ - nonum_[row] = !num; - if (nonum_[row]) - label_[row].clear(); -} - - -bool InsetMathHull::numbered(row_type row) const -{ - return !nonum_[row]; -} - - -bool InsetMathHull::ams() const -{ - return - type_ == hullAlign || - type_ == hullFlAlign || - type_ == hullMultline || - type_ == hullGather || - type_ == hullAlignAt || - type_ == hullXAlignAt || - type_ == hullXXAlignAt; -} - - -bool InsetMathHull::display() const -{ - return type_ != hullSimple && type_ != hullNone; -} - - -void InsetMathHull::getLabelList(Buffer const &, vector & labels) const -{ - for (row_type row = 0; row < nrows(); ++row) - if (!label_[row].empty() && nonum_[row] != 1) - labels.push_back(label_[row]); -} - - -bool InsetMathHull::numberedType() const -{ - if (type_ == hullNone) - return false; - if (type_ == hullSimple) - return false; - if (type_ == hullXXAlignAt) - return false; - for (row_type row = 0; row < nrows(); ++row) - if (!nonum_[row]) - return true; - return false; -} - - -void InsetMathHull::validate(LaTeXFeatures & features) const -{ - if (ams()) - features.require("amsmath"); - - - // Validation is necessary only if not using AMS math. - // To be safe, we will always run mathedvalidate. - //if (features.amsstyle) - // return; - - features.require("boldsymbol"); - //features.binom = true; - - InsetMathGrid::validate(features); -} - - -void InsetMathHull::header_write(WriteStream & os) const -{ - bool n = numberedType(); - - switch(type_) { - case hullNone: - break; - - case hullSimple: - os << '$'; - if (cell(0).empty()) - os << ' '; - break; - - case hullEquation: - if (n) - os << "\\begin{equation" << star(n) << "}\n"; - else - os << "\\[\n"; - break; - - case hullEqnArray: - case hullAlign: - case hullFlAlign: - case hullGather: - case hullMultline: - os << "\\begin{" << hullName(type_) << star(n) << "}\n"; - break; - - case hullAlignAt: - case hullXAlignAt: - os << "\\begin{" << hullName(type_) << star(n) << '}' - << '{' << static_cast((ncols() + 1)/2) << "}\n"; - break; - - case hullXXAlignAt: - os << "\\begin{" << hullName(type_) << '}' - << '{' << static_cast((ncols() + 1)/2) << "}\n"; - break; - - default: - os << "\\begin{unknown" << star(n) << '}'; - break; - } -} - - -void InsetMathHull::footer_write(WriteStream & os) const -{ - bool n = numberedType(); - - switch(type_) { - case hullNone: - os << "\n"; - break; - - case hullSimple: - os << '$'; - break; - - case hullEquation: - if (n) - os << "\\end{equation" << star(n) << "}\n"; - else - os << "\\]\n"; - break; - - case hullEqnArray: - case hullAlign: - case hullFlAlign: - case hullAlignAt: - case hullXAlignAt: - case hullGather: - case hullMultline: - os << "\\end{" << hullName(type_) << star(n) << "}\n"; - break; - - case hullXXAlignAt: - os << "\\end{" << hullName(type_) << "}\n"; - break; - - default: - os << "\\end{unknown" << star(n) << '}'; - break; - } -} - - -bool InsetMathHull::rowChangeOK() const -{ - return - type_ == hullEqnArray || type_ == hullAlign || - type_ == hullFlAlign || type_ == hullAlignAt || - type_ == hullXAlignAt || type_ == hullXXAlignAt || - type_ == hullGather || type_ == hullMultline; -} - - -bool InsetMathHull::colChangeOK() const -{ - return - type_ == hullAlign || type_ == hullFlAlign ||type_ == hullAlignAt || - type_ == hullXAlignAt || type_ == hullXXAlignAt; -} - - -void InsetMathHull::addRow(row_type row) -{ - if (!rowChangeOK()) - return; - nonum_.insert(nonum_.begin() + row + 1, !numberedType()); - label_.insert(label_.begin() + row + 1, docstring()); - InsetMathGrid::addRow(row); -} - - -void InsetMathHull::swapRow(row_type row) -{ - if (nrows() <= 1) - return; - if (row + 1 == nrows()) - --row; - swap(nonum_[row], nonum_[row + 1]); - swap(label_[row], label_[row + 1]); - InsetMathGrid::swapRow(row); -} - - -void InsetMathHull::delRow(row_type row) -{ - if (nrows() <= 1 || !rowChangeOK()) - return; - InsetMathGrid::delRow(row); - // The last dummy row has no number info nor a label. - // Test nrows() + 1 because we have already erased the row. - if (row == nrows() + 1) - row--; - nonum_.erase(nonum_.begin() + row); - label_.erase(label_.begin() + row); -} - - -void InsetMathHull::addCol(col_type col) -{ - if (!colChangeOK()) - return; - InsetMathGrid::addCol(col); -} - - -void InsetMathHull::delCol(col_type col) -{ - if (ncols() <= 1 || !colChangeOK()) - return; - InsetMathGrid::delCol(col); -} - - -docstring InsetMathHull::nicelabel(row_type row) const -{ - if (nonum_[row]) - return docstring(); - if (label_[row].empty()) - return from_ascii("(#)"); - return '(' + label_[row] + ')'; -} - - -void InsetMathHull::glueall() -{ - MathArray ar; - for (idx_type i = 0; i < nargs(); ++i) - ar.append(cell(i)); - *this = InsetMathHull(hullSimple); - cell(0) = ar; - setDefaults(); -} - - -void InsetMathHull::splitTo2Cols() -{ - BOOST_ASSERT(ncols() == 1); - InsetMathGrid::addCol(1); - for (row_type row = 0; row < nrows(); ++row) { - idx_type const i = 2 * row; - pos_type pos = firstRelOp(cell(i)); - cell(i + 1) = MathArray(cell(i).begin() + pos, cell(i).end()); - cell(i).erase(pos, cell(i).size()); - } -} - - -void InsetMathHull::splitTo3Cols() -{ - BOOST_ASSERT(ncols() < 3); - if (ncols() < 2) - splitTo2Cols(); - InsetMathGrid::addCol(1); - for (row_type row = 0; row < nrows(); ++row) { - idx_type const i = 3 * row + 1; - if (cell(i).size()) { - cell(i + 1) = MathArray(cell(i).begin() + 1, cell(i).end()); - cell(i).erase(1, cell(i).size()); - } - } -} - - -void InsetMathHull::changeCols(col_type cols) -{ - if (ncols() == cols) - return; - else if (ncols() < cols) { - // split columns - if (cols < 3) - splitTo2Cols(); - else { - splitTo3Cols(); - while (ncols() < cols) - InsetMathGrid::addCol(ncols() - 1); - } - return; - } - - // combine columns - for (row_type row = 0; row < nrows(); ++row) { - idx_type const i = row * ncols(); - for (col_type col = cols; col < ncols(); ++col) { - cell(i + cols - 1).append(cell(i + col)); - } - } - // delete columns - while (ncols() > cols) { - InsetMathGrid::delCol(ncols() - 1); - } -} - - -HullType InsetMathHull::getType() const -{ - return type_; -} - - -void InsetMathHull::setType(HullType type) -{ - type_ = type; - setDefaults(); -} - - -void InsetMathHull::mutate(HullType newtype) -{ - //lyxerr << "mutating from '" << type_ << "' to '" << newtype << "'" << endl; - - // we try to move along the chain - // none <-> simple <-> equation <-> eqnarray -> *align* -> multline, gather -+ - // ^ | - // +-------------------------------------+ - // we use eqnarray as intermediate type for mutations that are not - // directly supported because it handles labels and numbering for - // "down mutation". - - if (newtype == type_) { - // done - } - - else if (newtype < hullNone) { - // unknown type - dump(); - } - - else if (type_ == hullNone) { - setType(hullSimple); - numbered(0, false); - mutate(newtype); - } - - else if (type_ == hullSimple) { - if (newtype == hullNone) { - setType(hullNone); - numbered(0, false); - } else { - setType(hullEquation); - numbered(0, false); - mutate(newtype); - } - } - - else if (type_ == hullEquation) { - if (newtype < type_) { - setType(hullSimple); - numbered(0, false); - mutate(newtype); - } else if (newtype == hullEqnArray) { - // split it "nicely" on the first relop - splitTo3Cols(); - setType(hullEqnArray); - } else if (newtype == hullMultline || newtype == hullGather) { - setType(newtype); - } else { - // split it "nicely" - splitTo2Cols(); - setType(hullAlign); - mutate(newtype); - } - } - - else if (type_ == hullEqnArray) { - if (newtype < type_) { - // set correct (no)numbering - bool allnonum = true; - for (row_type row = 0; row < nrows(); ++row) - if (!nonum_[row]) - allnonum = false; - - // set first non-empty label - docstring label; - for (row_type row = 0; row < nrows(); ++row) { - if (!label_[row].empty()) { - label = label_[row]; - break; - } - } - - glueall(); - nonum_[0] = allnonum; - label_[0] = label; - mutate(newtype); - } else { // align & Co. - changeCols(2); - setType(hullAlign); - mutate(newtype); - } - } - - else if (type_ == hullAlign || type_ == hullAlignAt || - type_ == hullXAlignAt || type_ == hullFlAlign) { - if (newtype < hullAlign) { - changeCols(3); - setType(hullEqnArray); - mutate(newtype); - } else if (newtype == hullGather || newtype == hullMultline) { - changeCols(1); - setType(newtype); - } else if (newtype == hullXXAlignAt) { - for (row_type row = 0; row < nrows(); ++row) - numbered(row, false); - setType(newtype); - } else { - setType(newtype); - } - } - - else if (type_ == hullXXAlignAt) { - for (row_type row = 0; row < nrows(); ++row) - numbered(row, false); - if (newtype < hullAlign) { - changeCols(3); - setType(hullEqnArray); - mutate(newtype); - } else if (newtype == hullGather || newtype == hullMultline) { - changeCols(1); - setType(newtype); - } else { - setType(newtype); - } - } - - else if (type_ == hullMultline || type_ == hullGather) { - if (newtype == hullGather || newtype == hullMultline) - setType(newtype); - else if (newtype == hullAlign || newtype == hullFlAlign || - newtype == hullAlignAt || newtype == hullXAlignAt) { - splitTo2Cols(); - setType(newtype); - } else if (newtype == hullXXAlignAt) { - splitTo2Cols(); - for (row_type row = 0; row < nrows(); ++row) - numbered(row, false); - setType(newtype); - } else { - splitTo3Cols(); - setType(hullEqnArray); - mutate(newtype); - } - } - - else { - lyxerr << "mutation from '" << to_utf8(hullName(type_)) - << "' to '" << to_utf8(hullName(newtype)) - << "' not implemented" << endl; - } -} - - -docstring InsetMathHull::eolString(row_type row, bool emptyline, bool fragile) const -{ - docstring res; - if (numberedType()) { - if (!label_[row].empty() && !nonum_[row]) - res += "\\label{" + label_[row] + '}'; - if (nonum_[row] && (type_ != hullMultline)) - res += "\\nonumber "; - } - return res + InsetMathGrid::eolString(row, emptyline, fragile); -} - - -void InsetMathHull::write(WriteStream & os) const -{ - header_write(os); - InsetMathGrid::write(os); - footer_write(os); -} - - -void InsetMathHull::normalize(NormalStream & os) const -{ - os << "[formula " << hullName(type_) << ' '; - InsetMathGrid::normalize(os); - os << "] "; -} - - -void InsetMathHull::mathmlize(MathStream & os) const -{ - InsetMathGrid::mathmlize(os); -} - - -void InsetMathHull::infoize(odocstream & os) const -{ - os << "Type: " << hullName(type_); -} - - -void InsetMathHull::check() const -{ - BOOST_ASSERT(nonum_.size() == nrows()); - BOOST_ASSERT(label_.size() == nrows()); -} - - -void InsetMathHull::doExtern(LCursor & cur, FuncRequest & func) -{ - docstring dlang; - docstring extra; - idocstringstream iss(func.argument()); - iss >> dlang >> extra; - if (extra.empty()) - extra = from_ascii("noextra"); - std::string const lang = to_ascii(dlang); - -#ifdef WITH_WARNINGS -#warning temporarily disabled - //if (cur.selection()) { - // MathArray ar; - // selGet(cur.ar); - // lyxerr << "use selection: " << ar << endl; - // insert(pipeThroughExtern(lang, extra, ar)); - // return; - //} -#endif - - MathArray eq; - eq.push_back(MathAtom(new InsetMathChar('='))); - - // go to first item in line - cur.idx() -= cur.idx() % ncols(); - cur.pos() = 0; - - if (getType() == hullSimple) { - size_type pos = cur.cell().find_last(eq); - MathArray ar; - if (cur.inMathed() && cur.selection()) { - asArray(grabAndEraseSelection(cur), ar); - } else if (pos == cur.cell().size()) { - ar = cur.cell(); - lyxerr << "use whole cell: " << ar << endl; - } else { - ar = MathArray(cur.cell().begin() + pos + 1, cur.cell().end()); - lyxerr << "use partial cell form pos: " << pos << endl; - } - cur.cell().append(eq); - cur.cell().append(pipeThroughExtern(lang, extra, ar)); - cur.pos() = cur.lastpos(); - return; - } - - if (getType() == hullEquation) { - lyxerr << "use equation inset" << endl; - mutate(hullEqnArray); - MathArray & ar = cur.cell(); - lyxerr << "use cell: " << ar << endl; - ++cur.idx(); - cur.cell() = eq; - ++cur.idx(); - cur.cell() = pipeThroughExtern(lang, extra, ar); - // move to end of line - cur.pos() = cur.lastpos(); - return; - } - - { - lyxerr << "use eqnarray" << endl; - cur.idx() += 2 - cur.idx() % ncols(); - cur.pos() = 0; - MathArray ar = cur.cell(); - lyxerr << "use cell: " << ar << endl; -#ifdef WITH_WARNINGS -#warning temporarily disabled -#endif - addRow(cur.row()); - ++cur.idx(); - ++cur.idx(); - cur.cell() = eq; - ++cur.idx(); - cur.cell() = pipeThroughExtern(lang, extra, ar); - cur.pos() = cur.lastpos(); - } -} - - -void InsetMathHull::doDispatch(LCursor & cur, FuncRequest & cmd) -{ - //lyxerr << "action: " << cmd.action << endl; - switch (cmd.action) { - - case LFUN_FINISHED_LEFT: - case LFUN_FINISHED_RIGHT: - case LFUN_FINISHED_UP: - case LFUN_FINISHED_DOWN: - //lyxerr << "action: " << cmd.action << endl; - InsetMathGrid::doDispatch(cur, cmd); - notifyCursorLeaves(cur); - cur.undispatched(); - break; - - case LFUN_BREAK_PARAGRAPH: - // just swallow this - break; - - case LFUN_BREAK_LINE: - // some magic for the common case - if (type_ == hullSimple || type_ == hullEquation) { - recordUndoInset(cur); - bool const align = - cur.bv().buffer()->params().use_amsmath == BufferParams::package_on; - mutate(align ? hullAlign : hullEqnArray); - cur.idx() = 0; - cur.pos() = cur.lastpos(); - } - InsetMathGrid::doDispatch(cur, cmd); - break; - - case LFUN_MATH_NUMBER: - //lyxerr << "toggling all numbers" << endl; - if (display()) { - recordUndoInset(cur); - bool old = numberedType(); - if (type_ == hullMultline) - numbered(nrows() - 1, !old); - else - for (row_type row = 0; row < nrows(); ++row) - numbered(row, !old); - - cur.message(old ? _("No number") : _("Number")); - } - break; - - case LFUN_MATH_NONUMBER: - if (display()) { - recordUndoInset(cur); - row_type r = (type_ == hullMultline) ? nrows() - 1 : cur.row(); - bool old = numbered(r); - cur.message(old ? _("No number") : _("Number")); - numbered(r, !old); - } - break; - - case LFUN_LABEL_INSERT: { - recordUndoInset(cur); - row_type r = (type_ == hullMultline) ? nrows() - 1 : cur.row(); - docstring old_label = label(r); - docstring const default_label = from_ascii( - (lyxrc.label_init_length >= 0) ? "eq:" : ""); - if (old_label.empty()) - old_label = default_label; - - InsetCommandParams p("label"); - p["name"] = cmd.argument().empty() ? old_label : cmd.argument(); - std::string const data = InsetCommandMailer::params2string("label", p); - - if (cmd.argument().empty()) - cur.bv().showInsetDialog("label", data, 0); - else { - FuncRequest fr(LFUN_INSET_INSERT, data); - dispatch(cur, fr); - } - break; - } - - case LFUN_INSET_INSERT: { - //lyxerr << "arg: " << to_utf8(cmd.argument()) << endl; - std::string const name = cmd.getArg(0); - if (name == "label") { - InsetCommandParams p("label"); - InsetCommandMailer::string2params(name, to_utf8(cmd.argument()), p); - docstring str = p["name"]; - recordUndoInset(cur); - row_type const r = (type_ == hullMultline) ? nrows() - 1 : cur.row(); - str = support::trim(str); - if (!str.empty()) - numbered(r, true); - docstring old = label(r); - if (str != old) { - cur.bv().buffer()->changeRefsIfUnique(old, str, - InsetBase::REF_CODE); - label(r, str); - } - break; - } - InsetMathGrid::doDispatch(cur, cmd); - return; - } - - case LFUN_MATH_EXTERN: - recordUndoInset(cur); - doExtern(cur, cmd); - break; - - case LFUN_MATH_MUTATE: { - recordUndoInset(cur); - row_type row = cur.row(); - col_type col = cur.col(); - mutate(hullType(cmd.argument())); - cur.idx() = row * ncols() + col; - if (cur.idx() > cur.lastidx()) { - cur.idx() = cur.lastidx(); - cur.pos() = cur.lastpos(); - } - if (cur.pos() > cur.lastpos()) - cur.pos() = cur.lastpos(); - //cur.dispatched(FINISHED); - break; - } - - case LFUN_MATH_DISPLAY: { - recordUndoInset(cur); - mutate(type_ == hullSimple ? hullEquation : hullSimple); - cur.idx() = 0; - cur.pos() = cur.lastpos(); - //cur.dispatched(FINISHED); - break; - } - - default: - InsetMathGrid::doDispatch(cur, cmd); - break; - } -} - - -bool InsetMathHull::getStatus(LCursor & cur, FuncRequest const & cmd, - FuncStatus & status) const -{ - switch (cmd.action) { - case LFUN_FINISHED_LEFT: - case LFUN_FINISHED_RIGHT: - case LFUN_FINISHED_UP: - case LFUN_FINISHED_DOWN: - status.enabled(true); - return true; - case LFUN_BREAK_LINE: - case LFUN_MATH_NUMBER: - case LFUN_MATH_NONUMBER: - case LFUN_MATH_EXTERN: - case LFUN_MATH_MUTATE: - case LFUN_MATH_DISPLAY: - // we handle these - status.enabled(true); - return true; - case LFUN_LABEL_INSERT: - status.enabled(type_ != hullSimple); - return true; - case LFUN_INSET_INSERT: - if (cmd.getArg(0) == "label") { - status.enabled(type_ != hullSimple); - return true; - } - return InsetMathGrid::getStatus(cur, cmd, status); - case LFUN_TABULAR_FEATURE: { - istringstream is(to_utf8(cmd.argument())); - std::string s; - is >> s; - if (!rowChangeOK() - && (s == "append-row" - || s == "delete-row" - || s == "copy-row")) { - status.message(bformat( - from_utf8(N_("Can't change number of rows in '%1$s'")), - hullName(type_))); - status.enabled(false); - return true; - } - if (!colChangeOK() - && (s == "append-column" - || s == "delete-column" - || s == "copy-column")) { - status.message(bformat( - from_utf8(N_("Can't change number of columns in '%1$s'")), - hullName(type_))); - status.enabled(false); - return true; - } - if ((type_ == hullSimple - || type_ == hullEquation - || type_ == hullNone) && - (s == "add-hline-above" || s == "add-hline-below")) { - status.message(bformat( - from_utf8(N_("Can't add horizontal grid lines in '%1$s'")), - hullName(type_))); - status.enabled(false); - return true; - } - if (s == "add-vline-left" || s == "add-vline-right") { - status.message(bformat( - from_utf8(N_("Can't add vertical grid lines in '%1$s'")), - hullName(type_))); - status.enabled(false); - return true; - } - if (s == "valign-top" || s == "valign-middle" - || s == "valign-bottom" || s == "align-left" - || s == "align-center" || s == "align-right") { - status.enabled(false); - return true; - } - return InsetMathGrid::getStatus(cur, cmd, status); - } - default: - return InsetMathGrid::getStatus(cur, cmd, status); - } - - // This cannot really happen, but inserted to shut-up gcc - return InsetMathGrid::getStatus(cur, cmd, status); -} - - -///////////////////////////////////////////////////////////////////// - - - -// simply scrap this function if you want -void InsetMathHull::mutateToText() -{ -#if 0 - // translate to latex - ostringstream os; - latex(NULL, os, false, false); - string str = os.str(); - - // insert this text - LyXText * lt = view_->cursor().innerText(); - string::const_iterator cit = str.begin(); - string::const_iterator end = str.end(); - for (; cit != end; ++cit) - view_->getIntl()->getTransManager().TranslateAndInsert(*cit, lt); - - // remove ourselves - //dispatch(LFUN_ESCAPE); -#endif -} - - -void InsetMathHull::handleFont(LCursor & cur, docstring const & arg, - docstring const & font) -{ - // this whole function is a hack and won't work for incremental font - // changes... - recordUndo(cur); - if (cur.inset().asInsetMath()->name() == font) - cur.handleFont(to_utf8(font)); - else { - cur.handleNest(createInsetMath(font)); - cur.insert(arg); - } -} - - -void InsetMathHull::handleFont2(LCursor & cur, docstring const & arg) -{ - recordUndo(cur); - LyXFont font; - bool b; - bv_funcs::string2font(to_utf8(arg), font, b); - if (font.color() != LColor::inherit) { - MathAtom at = MathAtom(new InsetMathColor(true, font.color())); - cur.handleNest(at, 0); - } -} - - -void InsetMathHull::edit(LCursor & cur, bool left) -{ - cur.push(*this); - left ? idxFirst(cur) : idxLast(cur); - // The inset formula dimension is not necessarily the same as the - // one of the instant preview image, so we have to indicate to the - // BufferView that a metrics update is needed. - cur.updateFlags(Update::Force); -} - - -docstring const InsetMathHull::editMessage() const -{ - return _("Math editor mode"); -} - - -void InsetMathHull::revealCodes(LCursor & cur) const -{ - if (!cur.inMathed()) - return; - odocstringstream os; - cur.info(os); - cur.message(os.str()); -/* - // write something to the minibuffer - // translate to latex - cur.markInsert(bv); - ostringstream os; - write(NULL, os); - string str = os.str(); - cur.markErase(bv); - string::size_type pos = 0; - string res; - for (string::iterator it = str.begin(); it != str.end(); ++it) { - if (*it == '\n') - res += ' '; - else if (*it == '\0') { - res += " -X- "; - pos = it - str.begin(); - } - else - res += *it; - } - if (pos > 30) - res = res.substr(pos - 30); - if (res.size() > 60) - res = res.substr(0, 60); - cur.message(res); -*/ -} - - -InsetBase::Code InsetMathHull::lyxCode() const -{ - return MATH_CODE; -} - - -///////////////////////////////////////////////////////////////////// - - -#if 0 -bool InsetMathHull::searchForward(BufferView * bv, string const & str, - bool, bool) -{ -#ifdef WITH_WARNINGS -#warning completely broken -#endif - static InsetMathHull * lastformula = 0; - static CursorBase current = DocIterator(ibegin(nucleus())); - static MathArray ar; - static string laststr; - - if (lastformula != this || laststr != str) { - //lyxerr << "reset lastformula to " << this << endl; - lastformula = this; - laststr = str; - current = ibegin(nucleus()); - ar.clear(); - mathed_parse_cell(ar, str); - } else { - increment(current); - } - //lyxerr << "searching '" << str << "' in " << this << ar << endl; - - for (DocIterator it = current; it != iend(nucleus()); increment(it)) { - CursorSlice & top = it.back(); - MathArray const & a = top.asInsetMath()->cell(top.idx_); - if (a.matchpart(ar, top.pos_)) { - bv->cursor().setSelection(it, ar.size()); - current = it; - top.pos_ += ar.size(); - bv->update(); - return true; - } - } - - //lyxerr << "not found!" << endl; - lastformula = 0; - return false; -} -#endif - - -void InsetMathHull::write(Buffer const &, std::ostream & os) const -{ - odocstringstream oss; - WriteStream wi(oss, false, false); - oss << "Formula "; - write(wi); - os << to_utf8(oss.str()); -} - - -void InsetMathHull::read(Buffer const &, LyXLex & lex) -{ - MathAtom at; - mathed_parse_normal(at, lex); - operator=(*at->asHullInset()); -} - - -int InsetMathHull::plaintext(Buffer const &, odocstream & os, - OutputParams const &) const -{ - if (0 && display()) { - Dimension dim; - TextMetricsInfo mi; - metricsT(mi, dim); - TextPainter tpain(dim.width(), dim.height()); - drawT(tpain, 0, dim.ascent()); - tpain.show(os, 3); - // reset metrics cache to "real" values - //metrics(); - return tpain.textheight(); - } else { - odocstringstream oss; - WriteStream wi(oss, false, true); - wi << cell(0); - - docstring const str = oss.str(); - os << str; - return str.size(); - } -} - - -int InsetMathHull::docbook(Buffer const & buf, odocstream & os, - OutputParams const & runparams) const -{ - MathStream ms(os); - int res = 0; - docstring name; - if (getType() == hullSimple) - name = from_ascii("inlineequation"); - else - name = from_ascii("informalequation"); - - docstring bname = name; - if (!label(0).empty()) - bname += " id='" + sgml::cleanID(buf, runparams, label(0)) + "'"; - ms << MTag(bname); - - odocstringstream ls; - if (runparams.flavor == OutputParams::XML) { - ms << MTag(from_ascii("alt role='tex' ")); - // Workaround for db2latex: db2latex always includes equations with - // \ensuremath{} or \begin{display}\end{display} - // so we strip LyX' math environment - WriteStream wi(ls, false, false); - InsetMathGrid::write(wi); - ms << from_utf8(subst(subst(to_utf8(ls.str()), "&", "&"), "<", "<")); - ms << ETag(from_ascii("alt")); - ms << MTag(from_ascii("math")); - ms << ETag(from_ascii("alt")); - ms << MTag(from_ascii("math")); - InsetMathGrid::mathmlize(ms); - ms << ETag(from_ascii("math")); - } else { - ms << MTag(from_ascii("alt role='tex'")); - res = latex(buf, ls, runparams); - ms << from_utf8(subst(subst(to_utf8(ls.str()), "&", "&"), "<", "<")); - ms << ETag(from_ascii("alt")); - } - - ms << from_ascii(""); - else - ms << from_ascii("\">"); - - ms << ETag(name); - return ms.line() + res; -} - - -void InsetMathHull::textString(Buffer const & buf, odocstream & os) const -{ - plaintext(buf, os, OutputParams(0)); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathHull.cpp b/src/mathed/InsetMathHull.cpp new file mode 100644 index 0000000000..cd3a59081b --- /dev/null +++ b/src/mathed/InsetMathHull.cpp @@ -0,0 +1,1525 @@ +/** + * \file InsetMathHull.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathArray.h" +#include "InsetMathChar.h" +#include "InsetMathColor.h" +#include "MathData.h" +#include "InsetMathDelim.h" +#include "MathExtern.h" +#include "MathFactory.h" +#include "InsetMathHull.h" +#include "MathStream.h" +#include "MathParser.h" +#include "InsetMathSpace.h" +#include "MathStream.h" +#include "MathSupport.h" +#include "InsetMathRef.h" + +#include "bufferview_funcs.h" +#include "lyxtext.h" + +#include "buffer.h" +#include "bufferparams.h" +#include "BufferView.h" +#include "CutAndPaste.h" +#include "FuncStatus.h" +#include "LColor.h" +#include "LaTeXFeatures.h" +#include "cursor.h" +#include "debug.h" +#include "dispatchresult.h" +#include "funcrequest.h" +#include "gettext.h" +#include "lyxrc.h" +#include "outputparams.h" +#include "sgml.h" +#include "TextPainter.h" +#include "undo.h" + +#include "insets/RenderPreview.h" +#include "insets/InsetLabel.h" + +#include "graphics/PreviewImage.h" +#include "graphics/PreviewLoader.h" + +#include "support/lyxlib.h" +#include "support/lstrings.h" + +#include + +#include + + +namespace lyx { + +using cap::grabAndEraseSelection; +using support::bformat; +using support::subst; + +using std::endl; +using std::max; +using std::ostream; +using std::auto_ptr; +using std::istringstream; +using std::ostringstream; +using std::pair; +using std::swap; +using std::vector; + + +namespace { + + int getCols(HullType type) + { + switch (type) { + case hullEqnArray: + return 3; + case hullAlign: + case hullFlAlign: + case hullAlignAt: + case hullXAlignAt: + case hullXXAlignAt: + return 2; + default: + return 1; + } + } + + + // returns position of first relation operator in the array + // used for "intelligent splitting" + size_t firstRelOp(MathArray const & ar) + { + for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) + if ((*it)->isRelOp()) + return it - ar.begin(); + return ar.size(); + } + + + char const * star(bool numbered) + { + return numbered ? "" : "*"; + } + + +} // end anon namespace + + +HullType hullType(docstring const & s) +{ + if (s == "none") return hullNone; + if (s == "simple") return hullSimple; + if (s == "equation") return hullEquation; + if (s == "eqnarray") return hullEqnArray; + if (s == "align") return hullAlign; + if (s == "alignat") return hullAlignAt; + if (s == "xalignat") return hullXAlignAt; + if (s == "xxalignat") return hullXXAlignAt; + if (s == "multline") return hullMultline; + if (s == "gather") return hullGather; + if (s == "flalign") return hullFlAlign; + lyxerr << "unknown hull type '" << to_utf8(s) << "'" << endl; + return HullType(-1); +} + + +docstring hullName(HullType type) +{ + switch (type) { + case hullNone: return from_ascii("none"); + case hullSimple: return from_ascii("simple"); + case hullEquation: return from_ascii("equation"); + case hullEqnArray: return from_ascii("eqnarray"); + case hullAlign: return from_ascii("align"); + case hullAlignAt: return from_ascii("alignat"); + case hullXAlignAt: return from_ascii("xalignat"); + case hullXXAlignAt: return from_ascii("xxalignat"); + case hullMultline: return from_ascii("multline"); + case hullGather: return from_ascii("gather"); + case hullFlAlign: return from_ascii("flalign"); + default: + lyxerr << "unknown hull type '" << type << "'" << endl; + return from_ascii("none"); + } +} + + +InsetMathHull::InsetMathHull() + : InsetMathGrid(1, 1), type_(hullNone), nonum_(1), label_(1), + preview_(new RenderPreview(this)) +{ + //lyxerr << "sizeof InsetMath: " << sizeof(InsetMath) << endl; + //lyxerr << "sizeof MetricsInfo: " << sizeof(MetricsInfo) << endl; + //lyxerr << "sizeof InsetMathChar: " << sizeof(InsetMathChar) << endl; + //lyxerr << "sizeof LyXFont: " << sizeof(LyXFont) << endl; + initMath(); + setDefaults(); +} + + +InsetMathHull::InsetMathHull(HullType type) + : InsetMathGrid(getCols(type), 1), type_(type), nonum_(1), label_(1), + preview_(new RenderPreview(this)) +{ + initMath(); + setDefaults(); +} + + +InsetMathHull::InsetMathHull(InsetMathHull const & other) + : InsetMathGrid(other), + type_(other.type_), nonum_(other.nonum_), label_(other.label_), + preview_(new RenderPreview(this)) +{} + + +InsetMathHull::~InsetMathHull() +{} + + +auto_ptr InsetMathHull::doClone() const +{ + return auto_ptr(new InsetMathHull(*this)); +} + + +InsetMathHull & InsetMathHull::operator=(InsetMathHull const & other) +{ + if (this == &other) + return *this; + *static_cast(this) = InsetMathGrid(other); + type_ = other.type_; + nonum_ = other.nonum_; + label_ = other.label_; + preview_.reset(new RenderPreview(*other.preview_, this)); + + return *this; +} + + +InsetBase * InsetMathHull::editXY(LCursor & cur, int x, int y) +{ + if (use_preview_) { + edit(cur, true); + return this; + } + return InsetMathNest::editXY(cur, x, y); +} + + +InsetMath::mode_type InsetMathHull::currentMode() const +{ + if (type_ == hullNone) + return UNDECIDED_MODE; + // definitely math mode ... + return MATH_MODE; +} + + +bool InsetMathHull::idxFirst(LCursor & cur) const +{ + cur.idx() = 0; + cur.pos() = 0; + return true; +} + + +bool InsetMathHull::idxLast(LCursor & cur) const +{ + cur.idx() = nargs() - 1; + cur.pos() = cur.lastpos(); + return true; +} + + +char InsetMathHull::defaultColAlign(col_type col) +{ + if (type_ == hullEqnArray) + return "rcl"[col]; + if (type_ >= hullAlign) + return "rl"[col & 1]; + return 'c'; +} + + +int InsetMathHull::defaultColSpace(col_type col) +{ + if (type_ == hullAlign || type_ == hullAlignAt) + return 0; + if (type_ == hullXAlignAt) + return (col & 1) ? 20 : 0; + if (type_ == hullXXAlignAt || type_ == hullFlAlign) + return (col & 1) ? 40 : 0; + return 0; +} + + +docstring InsetMathHull::standardFont() const +{ + return from_ascii(type_ == hullNone ? "lyxnochange" : "mathnormal"); +} + + +bool InsetMathHull::previewState(BufferView * bv) const +{ + if (!editing(bv) && RenderPreview::status() == LyXRC::PREVIEW_ON) { + graphics::PreviewImage const * pimage = + preview_->getPreviewImage(*bv->buffer()); + return pimage && pimage->image(); + } + return false; +} + + +bool InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const +{ + if (previewState(mi.base.bv)) { + preview_->metrics(mi, dim); + // insert a one pixel gap in front of the formula + dim.wid += 1; + if (display()) + dim.des += displayMargin(); + if (dim_ == dim) + return false; + dim_ = dim; + return true; + } + + FontSetChanger dummy1(mi.base, standardFont()); + StyleChanger dummy2(mi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT); + + // let the cells adjust themselves + InsetMathGrid::metrics(mi, dim); + + if (display()) { + dim.asc += displayMargin(); + dim.des += displayMargin(); + } + + if (numberedType()) { + FontSetChanger dummy(mi.base, from_ascii("mathbf")); + int l = 0; + for (row_type row = 0; row < nrows(); ++row) + l = max(l, mathed_string_width(mi.base.font, nicelabel(row))); + + if (l) + dim.wid += 30 + l; + } + + // make it at least as high as the current font + int asc = 0; + int des = 0; + math_font_max_dim(mi.base.font, asc, des); + dim.asc = max(dim.asc, asc); + dim.des = max(dim.des, des); + + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathHull::draw(PainterInfo & pi, int x, int y) const +{ + use_preview_ = previewState(pi.base.bv); + + if (use_preview_) { + // one pixel gap in front + preview_->draw(pi, x + 1, y); + setPosCache(pi, x, y); + return; + } + + FontSetChanger dummy1(pi.base, standardFont()); + StyleChanger dummy2(pi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT); + InsetMathGrid::draw(pi, x + 1, y); + + if (numberedType()) { + int const xx = x + colinfo_.back().offset_ + colinfo_.back().width_ + 20; + for (row_type row = 0; row < nrows(); ++row) { + int const yy = y + rowinfo_[row].offset_; + FontSetChanger dummy(pi.base, from_ascii("mathrm")); + docstring const nl = nicelabel(row); + pi.draw(xx, yy, nl); + } + } + setPosCache(pi, x, y); +} + + +void InsetMathHull::metricsT(TextMetricsInfo const & mi, Dimension & dim) const +{ + if (display()) { + InsetMathGrid::metricsT(mi, dim); + } else { + odocstringstream os; + WriteStream wi(os, false, true); + write(wi); + dim.wid = os.str().size(); + dim.asc = 1; + dim.des = 0; + } +} + + +void InsetMathHull::drawT(TextPainter & pain, int x, int y) const +{ + if (display()) { + InsetMathGrid::drawT(pain, x, y); + } else { + odocstringstream os; + WriteStream wi(os, false, true); + write(wi); + pain.draw(x, y, os.str().c_str()); + } +} + + +namespace { + +docstring const latex_string(InsetMathHull const & inset) +{ + odocstringstream ls; + WriteStream wi(ls, false, false); + inset.write(wi); + return ls.str(); +} + +} // namespace anon + + +void InsetMathHull::addPreview(graphics::PreviewLoader & ploader) const +{ + if (RenderPreview::status() == LyXRC::PREVIEW_ON) { + docstring const snippet = latex_string(*this); + preview_->addPreview(snippet, ploader); + } +} + + +bool InsetMathHull::notifyCursorLeaves(LCursor & cur) +{ + if (RenderPreview::status() == LyXRC::PREVIEW_ON) { + Buffer const & buffer = cur.buffer(); + docstring const snippet = latex_string(*this); + preview_->addPreview(snippet, buffer); + preview_->startLoading(buffer); + cur.updateFlags(Update::Force); + } + return false; +} + + +docstring InsetMathHull::label(row_type row) const +{ + BOOST_ASSERT(row < nrows()); + return label_[row]; +} + + +void InsetMathHull::label(row_type row, docstring const & label) +{ + //lyxerr << "setting label '" << label << "' for row " << row << endl; + label_[row] = label; +} + + +void InsetMathHull::numbered(row_type row, bool num) +{ + nonum_[row] = !num; + if (nonum_[row]) + label_[row].clear(); +} + + +bool InsetMathHull::numbered(row_type row) const +{ + return !nonum_[row]; +} + + +bool InsetMathHull::ams() const +{ + return + type_ == hullAlign || + type_ == hullFlAlign || + type_ == hullMultline || + type_ == hullGather || + type_ == hullAlignAt || + type_ == hullXAlignAt || + type_ == hullXXAlignAt; +} + + +bool InsetMathHull::display() const +{ + return type_ != hullSimple && type_ != hullNone; +} + + +void InsetMathHull::getLabelList(Buffer const &, vector & labels) const +{ + for (row_type row = 0; row < nrows(); ++row) + if (!label_[row].empty() && nonum_[row] != 1) + labels.push_back(label_[row]); +} + + +bool InsetMathHull::numberedType() const +{ + if (type_ == hullNone) + return false; + if (type_ == hullSimple) + return false; + if (type_ == hullXXAlignAt) + return false; + for (row_type row = 0; row < nrows(); ++row) + if (!nonum_[row]) + return true; + return false; +} + + +void InsetMathHull::validate(LaTeXFeatures & features) const +{ + if (ams()) + features.require("amsmath"); + + + // Validation is necessary only if not using AMS math. + // To be safe, we will always run mathedvalidate. + //if (features.amsstyle) + // return; + + features.require("boldsymbol"); + //features.binom = true; + + InsetMathGrid::validate(features); +} + + +void InsetMathHull::header_write(WriteStream & os) const +{ + bool n = numberedType(); + + switch(type_) { + case hullNone: + break; + + case hullSimple: + os << '$'; + if (cell(0).empty()) + os << ' '; + break; + + case hullEquation: + if (n) + os << "\\begin{equation" << star(n) << "}\n"; + else + os << "\\[\n"; + break; + + case hullEqnArray: + case hullAlign: + case hullFlAlign: + case hullGather: + case hullMultline: + os << "\\begin{" << hullName(type_) << star(n) << "}\n"; + break; + + case hullAlignAt: + case hullXAlignAt: + os << "\\begin{" << hullName(type_) << star(n) << '}' + << '{' << static_cast((ncols() + 1)/2) << "}\n"; + break; + + case hullXXAlignAt: + os << "\\begin{" << hullName(type_) << '}' + << '{' << static_cast((ncols() + 1)/2) << "}\n"; + break; + + default: + os << "\\begin{unknown" << star(n) << '}'; + break; + } +} + + +void InsetMathHull::footer_write(WriteStream & os) const +{ + bool n = numberedType(); + + switch(type_) { + case hullNone: + os << "\n"; + break; + + case hullSimple: + os << '$'; + break; + + case hullEquation: + if (n) + os << "\\end{equation" << star(n) << "}\n"; + else + os << "\\]\n"; + break; + + case hullEqnArray: + case hullAlign: + case hullFlAlign: + case hullAlignAt: + case hullXAlignAt: + case hullGather: + case hullMultline: + os << "\\end{" << hullName(type_) << star(n) << "}\n"; + break; + + case hullXXAlignAt: + os << "\\end{" << hullName(type_) << "}\n"; + break; + + default: + os << "\\end{unknown" << star(n) << '}'; + break; + } +} + + +bool InsetMathHull::rowChangeOK() const +{ + return + type_ == hullEqnArray || type_ == hullAlign || + type_ == hullFlAlign || type_ == hullAlignAt || + type_ == hullXAlignAt || type_ == hullXXAlignAt || + type_ == hullGather || type_ == hullMultline; +} + + +bool InsetMathHull::colChangeOK() const +{ + return + type_ == hullAlign || type_ == hullFlAlign ||type_ == hullAlignAt || + type_ == hullXAlignAt || type_ == hullXXAlignAt; +} + + +void InsetMathHull::addRow(row_type row) +{ + if (!rowChangeOK()) + return; + nonum_.insert(nonum_.begin() + row + 1, !numberedType()); + label_.insert(label_.begin() + row + 1, docstring()); + InsetMathGrid::addRow(row); +} + + +void InsetMathHull::swapRow(row_type row) +{ + if (nrows() <= 1) + return; + if (row + 1 == nrows()) + --row; + swap(nonum_[row], nonum_[row + 1]); + swap(label_[row], label_[row + 1]); + InsetMathGrid::swapRow(row); +} + + +void InsetMathHull::delRow(row_type row) +{ + if (nrows() <= 1 || !rowChangeOK()) + return; + InsetMathGrid::delRow(row); + // The last dummy row has no number info nor a label. + // Test nrows() + 1 because we have already erased the row. + if (row == nrows() + 1) + row--; + nonum_.erase(nonum_.begin() + row); + label_.erase(label_.begin() + row); +} + + +void InsetMathHull::addCol(col_type col) +{ + if (!colChangeOK()) + return; + InsetMathGrid::addCol(col); +} + + +void InsetMathHull::delCol(col_type col) +{ + if (ncols() <= 1 || !colChangeOK()) + return; + InsetMathGrid::delCol(col); +} + + +docstring InsetMathHull::nicelabel(row_type row) const +{ + if (nonum_[row]) + return docstring(); + if (label_[row].empty()) + return from_ascii("(#)"); + return '(' + label_[row] + ')'; +} + + +void InsetMathHull::glueall() +{ + MathArray ar; + for (idx_type i = 0; i < nargs(); ++i) + ar.append(cell(i)); + *this = InsetMathHull(hullSimple); + cell(0) = ar; + setDefaults(); +} + + +void InsetMathHull::splitTo2Cols() +{ + BOOST_ASSERT(ncols() == 1); + InsetMathGrid::addCol(1); + for (row_type row = 0; row < nrows(); ++row) { + idx_type const i = 2 * row; + pos_type pos = firstRelOp(cell(i)); + cell(i + 1) = MathArray(cell(i).begin() + pos, cell(i).end()); + cell(i).erase(pos, cell(i).size()); + } +} + + +void InsetMathHull::splitTo3Cols() +{ + BOOST_ASSERT(ncols() < 3); + if (ncols() < 2) + splitTo2Cols(); + InsetMathGrid::addCol(1); + for (row_type row = 0; row < nrows(); ++row) { + idx_type const i = 3 * row + 1; + if (cell(i).size()) { + cell(i + 1) = MathArray(cell(i).begin() + 1, cell(i).end()); + cell(i).erase(1, cell(i).size()); + } + } +} + + +void InsetMathHull::changeCols(col_type cols) +{ + if (ncols() == cols) + return; + else if (ncols() < cols) { + // split columns + if (cols < 3) + splitTo2Cols(); + else { + splitTo3Cols(); + while (ncols() < cols) + InsetMathGrid::addCol(ncols() - 1); + } + return; + } + + // combine columns + for (row_type row = 0; row < nrows(); ++row) { + idx_type const i = row * ncols(); + for (col_type col = cols; col < ncols(); ++col) { + cell(i + cols - 1).append(cell(i + col)); + } + } + // delete columns + while (ncols() > cols) { + InsetMathGrid::delCol(ncols() - 1); + } +} + + +HullType InsetMathHull::getType() const +{ + return type_; +} + + +void InsetMathHull::setType(HullType type) +{ + type_ = type; + setDefaults(); +} + + +void InsetMathHull::mutate(HullType newtype) +{ + //lyxerr << "mutating from '" << type_ << "' to '" << newtype << "'" << endl; + + // we try to move along the chain + // none <-> simple <-> equation <-> eqnarray -> *align* -> multline, gather -+ + // ^ | + // +-------------------------------------+ + // we use eqnarray as intermediate type for mutations that are not + // directly supported because it handles labels and numbering for + // "down mutation". + + if (newtype == type_) { + // done + } + + else if (newtype < hullNone) { + // unknown type + dump(); + } + + else if (type_ == hullNone) { + setType(hullSimple); + numbered(0, false); + mutate(newtype); + } + + else if (type_ == hullSimple) { + if (newtype == hullNone) { + setType(hullNone); + numbered(0, false); + } else { + setType(hullEquation); + numbered(0, false); + mutate(newtype); + } + } + + else if (type_ == hullEquation) { + if (newtype < type_) { + setType(hullSimple); + numbered(0, false); + mutate(newtype); + } else if (newtype == hullEqnArray) { + // split it "nicely" on the first relop + splitTo3Cols(); + setType(hullEqnArray); + } else if (newtype == hullMultline || newtype == hullGather) { + setType(newtype); + } else { + // split it "nicely" + splitTo2Cols(); + setType(hullAlign); + mutate(newtype); + } + } + + else if (type_ == hullEqnArray) { + if (newtype < type_) { + // set correct (no)numbering + bool allnonum = true; + for (row_type row = 0; row < nrows(); ++row) + if (!nonum_[row]) + allnonum = false; + + // set first non-empty label + docstring label; + for (row_type row = 0; row < nrows(); ++row) { + if (!label_[row].empty()) { + label = label_[row]; + break; + } + } + + glueall(); + nonum_[0] = allnonum; + label_[0] = label; + mutate(newtype); + } else { // align & Co. + changeCols(2); + setType(hullAlign); + mutate(newtype); + } + } + + else if (type_ == hullAlign || type_ == hullAlignAt || + type_ == hullXAlignAt || type_ == hullFlAlign) { + if (newtype < hullAlign) { + changeCols(3); + setType(hullEqnArray); + mutate(newtype); + } else if (newtype == hullGather || newtype == hullMultline) { + changeCols(1); + setType(newtype); + } else if (newtype == hullXXAlignAt) { + for (row_type row = 0; row < nrows(); ++row) + numbered(row, false); + setType(newtype); + } else { + setType(newtype); + } + } + + else if (type_ == hullXXAlignAt) { + for (row_type row = 0; row < nrows(); ++row) + numbered(row, false); + if (newtype < hullAlign) { + changeCols(3); + setType(hullEqnArray); + mutate(newtype); + } else if (newtype == hullGather || newtype == hullMultline) { + changeCols(1); + setType(newtype); + } else { + setType(newtype); + } + } + + else if (type_ == hullMultline || type_ == hullGather) { + if (newtype == hullGather || newtype == hullMultline) + setType(newtype); + else if (newtype == hullAlign || newtype == hullFlAlign || + newtype == hullAlignAt || newtype == hullXAlignAt) { + splitTo2Cols(); + setType(newtype); + } else if (newtype == hullXXAlignAt) { + splitTo2Cols(); + for (row_type row = 0; row < nrows(); ++row) + numbered(row, false); + setType(newtype); + } else { + splitTo3Cols(); + setType(hullEqnArray); + mutate(newtype); + } + } + + else { + lyxerr << "mutation from '" << to_utf8(hullName(type_)) + << "' to '" << to_utf8(hullName(newtype)) + << "' not implemented" << endl; + } +} + + +docstring InsetMathHull::eolString(row_type row, bool emptyline, bool fragile) const +{ + docstring res; + if (numberedType()) { + if (!label_[row].empty() && !nonum_[row]) + res += "\\label{" + label_[row] + '}'; + if (nonum_[row] && (type_ != hullMultline)) + res += "\\nonumber "; + } + return res + InsetMathGrid::eolString(row, emptyline, fragile); +} + + +void InsetMathHull::write(WriteStream & os) const +{ + header_write(os); + InsetMathGrid::write(os); + footer_write(os); +} + + +void InsetMathHull::normalize(NormalStream & os) const +{ + os << "[formula " << hullName(type_) << ' '; + InsetMathGrid::normalize(os); + os << "] "; +} + + +void InsetMathHull::mathmlize(MathStream & os) const +{ + InsetMathGrid::mathmlize(os); +} + + +void InsetMathHull::infoize(odocstream & os) const +{ + os << "Type: " << hullName(type_); +} + + +void InsetMathHull::check() const +{ + BOOST_ASSERT(nonum_.size() == nrows()); + BOOST_ASSERT(label_.size() == nrows()); +} + + +void InsetMathHull::doExtern(LCursor & cur, FuncRequest & func) +{ + docstring dlang; + docstring extra; + idocstringstream iss(func.argument()); + iss >> dlang >> extra; + if (extra.empty()) + extra = from_ascii("noextra"); + std::string const lang = to_ascii(dlang); + +#ifdef WITH_WARNINGS +#warning temporarily disabled + //if (cur.selection()) { + // MathArray ar; + // selGet(cur.ar); + // lyxerr << "use selection: " << ar << endl; + // insert(pipeThroughExtern(lang, extra, ar)); + // return; + //} +#endif + + MathArray eq; + eq.push_back(MathAtom(new InsetMathChar('='))); + + // go to first item in line + cur.idx() -= cur.idx() % ncols(); + cur.pos() = 0; + + if (getType() == hullSimple) { + size_type pos = cur.cell().find_last(eq); + MathArray ar; + if (cur.inMathed() && cur.selection()) { + asArray(grabAndEraseSelection(cur), ar); + } else if (pos == cur.cell().size()) { + ar = cur.cell(); + lyxerr << "use whole cell: " << ar << endl; + } else { + ar = MathArray(cur.cell().begin() + pos + 1, cur.cell().end()); + lyxerr << "use partial cell form pos: " << pos << endl; + } + cur.cell().append(eq); + cur.cell().append(pipeThroughExtern(lang, extra, ar)); + cur.pos() = cur.lastpos(); + return; + } + + if (getType() == hullEquation) { + lyxerr << "use equation inset" << endl; + mutate(hullEqnArray); + MathArray & ar = cur.cell(); + lyxerr << "use cell: " << ar << endl; + ++cur.idx(); + cur.cell() = eq; + ++cur.idx(); + cur.cell() = pipeThroughExtern(lang, extra, ar); + // move to end of line + cur.pos() = cur.lastpos(); + return; + } + + { + lyxerr << "use eqnarray" << endl; + cur.idx() += 2 - cur.idx() % ncols(); + cur.pos() = 0; + MathArray ar = cur.cell(); + lyxerr << "use cell: " << ar << endl; +#ifdef WITH_WARNINGS +#warning temporarily disabled +#endif + addRow(cur.row()); + ++cur.idx(); + ++cur.idx(); + cur.cell() = eq; + ++cur.idx(); + cur.cell() = pipeThroughExtern(lang, extra, ar); + cur.pos() = cur.lastpos(); + } +} + + +void InsetMathHull::doDispatch(LCursor & cur, FuncRequest & cmd) +{ + //lyxerr << "action: " << cmd.action << endl; + switch (cmd.action) { + + case LFUN_FINISHED_LEFT: + case LFUN_FINISHED_RIGHT: + case LFUN_FINISHED_UP: + case LFUN_FINISHED_DOWN: + //lyxerr << "action: " << cmd.action << endl; + InsetMathGrid::doDispatch(cur, cmd); + notifyCursorLeaves(cur); + cur.undispatched(); + break; + + case LFUN_BREAK_PARAGRAPH: + // just swallow this + break; + + case LFUN_BREAK_LINE: + // some magic for the common case + if (type_ == hullSimple || type_ == hullEquation) { + recordUndoInset(cur); + bool const align = + cur.bv().buffer()->params().use_amsmath == BufferParams::package_on; + mutate(align ? hullAlign : hullEqnArray); + cur.idx() = 0; + cur.pos() = cur.lastpos(); + } + InsetMathGrid::doDispatch(cur, cmd); + break; + + case LFUN_MATH_NUMBER: + //lyxerr << "toggling all numbers" << endl; + if (display()) { + recordUndoInset(cur); + bool old = numberedType(); + if (type_ == hullMultline) + numbered(nrows() - 1, !old); + else + for (row_type row = 0; row < nrows(); ++row) + numbered(row, !old); + + cur.message(old ? _("No number") : _("Number")); + } + break; + + case LFUN_MATH_NONUMBER: + if (display()) { + recordUndoInset(cur); + row_type r = (type_ == hullMultline) ? nrows() - 1 : cur.row(); + bool old = numbered(r); + cur.message(old ? _("No number") : _("Number")); + numbered(r, !old); + } + break; + + case LFUN_LABEL_INSERT: { + recordUndoInset(cur); + row_type r = (type_ == hullMultline) ? nrows() - 1 : cur.row(); + docstring old_label = label(r); + docstring const default_label = from_ascii( + (lyxrc.label_init_length >= 0) ? "eq:" : ""); + if (old_label.empty()) + old_label = default_label; + + InsetCommandParams p("label"); + p["name"] = cmd.argument().empty() ? old_label : cmd.argument(); + std::string const data = InsetCommandMailer::params2string("label", p); + + if (cmd.argument().empty()) + cur.bv().showInsetDialog("label", data, 0); + else { + FuncRequest fr(LFUN_INSET_INSERT, data); + dispatch(cur, fr); + } + break; + } + + case LFUN_INSET_INSERT: { + //lyxerr << "arg: " << to_utf8(cmd.argument()) << endl; + std::string const name = cmd.getArg(0); + if (name == "label") { + InsetCommandParams p("label"); + InsetCommandMailer::string2params(name, to_utf8(cmd.argument()), p); + docstring str = p["name"]; + recordUndoInset(cur); + row_type const r = (type_ == hullMultline) ? nrows() - 1 : cur.row(); + str = support::trim(str); + if (!str.empty()) + numbered(r, true); + docstring old = label(r); + if (str != old) { + cur.bv().buffer()->changeRefsIfUnique(old, str, + InsetBase::REF_CODE); + label(r, str); + } + break; + } + InsetMathGrid::doDispatch(cur, cmd); + return; + } + + case LFUN_MATH_EXTERN: + recordUndoInset(cur); + doExtern(cur, cmd); + break; + + case LFUN_MATH_MUTATE: { + recordUndoInset(cur); + row_type row = cur.row(); + col_type col = cur.col(); + mutate(hullType(cmd.argument())); + cur.idx() = row * ncols() + col; + if (cur.idx() > cur.lastidx()) { + cur.idx() = cur.lastidx(); + cur.pos() = cur.lastpos(); + } + if (cur.pos() > cur.lastpos()) + cur.pos() = cur.lastpos(); + //cur.dispatched(FINISHED); + break; + } + + case LFUN_MATH_DISPLAY: { + recordUndoInset(cur); + mutate(type_ == hullSimple ? hullEquation : hullSimple); + cur.idx() = 0; + cur.pos() = cur.lastpos(); + //cur.dispatched(FINISHED); + break; + } + + default: + InsetMathGrid::doDispatch(cur, cmd); + break; + } +} + + +bool InsetMathHull::getStatus(LCursor & cur, FuncRequest const & cmd, + FuncStatus & status) const +{ + switch (cmd.action) { + case LFUN_FINISHED_LEFT: + case LFUN_FINISHED_RIGHT: + case LFUN_FINISHED_UP: + case LFUN_FINISHED_DOWN: + status.enabled(true); + return true; + case LFUN_BREAK_LINE: + case LFUN_MATH_NUMBER: + case LFUN_MATH_NONUMBER: + case LFUN_MATH_EXTERN: + case LFUN_MATH_MUTATE: + case LFUN_MATH_DISPLAY: + // we handle these + status.enabled(true); + return true; + case LFUN_LABEL_INSERT: + status.enabled(type_ != hullSimple); + return true; + case LFUN_INSET_INSERT: + if (cmd.getArg(0) == "label") { + status.enabled(type_ != hullSimple); + return true; + } + return InsetMathGrid::getStatus(cur, cmd, status); + case LFUN_TABULAR_FEATURE: { + istringstream is(to_utf8(cmd.argument())); + std::string s; + is >> s; + if (!rowChangeOK() + && (s == "append-row" + || s == "delete-row" + || s == "copy-row")) { + status.message(bformat( + from_utf8(N_("Can't change number of rows in '%1$s'")), + hullName(type_))); + status.enabled(false); + return true; + } + if (!colChangeOK() + && (s == "append-column" + || s == "delete-column" + || s == "copy-column")) { + status.message(bformat( + from_utf8(N_("Can't change number of columns in '%1$s'")), + hullName(type_))); + status.enabled(false); + return true; + } + if ((type_ == hullSimple + || type_ == hullEquation + || type_ == hullNone) && + (s == "add-hline-above" || s == "add-hline-below")) { + status.message(bformat( + from_utf8(N_("Can't add horizontal grid lines in '%1$s'")), + hullName(type_))); + status.enabled(false); + return true; + } + if (s == "add-vline-left" || s == "add-vline-right") { + status.message(bformat( + from_utf8(N_("Can't add vertical grid lines in '%1$s'")), + hullName(type_))); + status.enabled(false); + return true; + } + if (s == "valign-top" || s == "valign-middle" + || s == "valign-bottom" || s == "align-left" + || s == "align-center" || s == "align-right") { + status.enabled(false); + return true; + } + return InsetMathGrid::getStatus(cur, cmd, status); + } + default: + return InsetMathGrid::getStatus(cur, cmd, status); + } + + // This cannot really happen, but inserted to shut-up gcc + return InsetMathGrid::getStatus(cur, cmd, status); +} + + +///////////////////////////////////////////////////////////////////// + + + +// simply scrap this function if you want +void InsetMathHull::mutateToText() +{ +#if 0 + // translate to latex + ostringstream os; + latex(NULL, os, false, false); + string str = os.str(); + + // insert this text + LyXText * lt = view_->cursor().innerText(); + string::const_iterator cit = str.begin(); + string::const_iterator end = str.end(); + for (; cit != end; ++cit) + view_->getIntl()->getTransManager().TranslateAndInsert(*cit, lt); + + // remove ourselves + //dispatch(LFUN_ESCAPE); +#endif +} + + +void InsetMathHull::handleFont(LCursor & cur, docstring const & arg, + docstring const & font) +{ + // this whole function is a hack and won't work for incremental font + // changes... + recordUndo(cur); + if (cur.inset().asInsetMath()->name() == font) + cur.handleFont(to_utf8(font)); + else { + cur.handleNest(createInsetMath(font)); + cur.insert(arg); + } +} + + +void InsetMathHull::handleFont2(LCursor & cur, docstring const & arg) +{ + recordUndo(cur); + LyXFont font; + bool b; + bv_funcs::string2font(to_utf8(arg), font, b); + if (font.color() != LColor::inherit) { + MathAtom at = MathAtom(new InsetMathColor(true, font.color())); + cur.handleNest(at, 0); + } +} + + +void InsetMathHull::edit(LCursor & cur, bool left) +{ + cur.push(*this); + left ? idxFirst(cur) : idxLast(cur); + // The inset formula dimension is not necessarily the same as the + // one of the instant preview image, so we have to indicate to the + // BufferView that a metrics update is needed. + cur.updateFlags(Update::Force); +} + + +docstring const InsetMathHull::editMessage() const +{ + return _("Math editor mode"); +} + + +void InsetMathHull::revealCodes(LCursor & cur) const +{ + if (!cur.inMathed()) + return; + odocstringstream os; + cur.info(os); + cur.message(os.str()); +/* + // write something to the minibuffer + // translate to latex + cur.markInsert(bv); + ostringstream os; + write(NULL, os); + string str = os.str(); + cur.markErase(bv); + string::size_type pos = 0; + string res; + for (string::iterator it = str.begin(); it != str.end(); ++it) { + if (*it == '\n') + res += ' '; + else if (*it == '\0') { + res += " -X- "; + pos = it - str.begin(); + } + else + res += *it; + } + if (pos > 30) + res = res.substr(pos - 30); + if (res.size() > 60) + res = res.substr(0, 60); + cur.message(res); +*/ +} + + +InsetBase::Code InsetMathHull::lyxCode() const +{ + return MATH_CODE; +} + + +///////////////////////////////////////////////////////////////////// + + +#if 0 +bool InsetMathHull::searchForward(BufferView * bv, string const & str, + bool, bool) +{ +#ifdef WITH_WARNINGS +#warning completely broken +#endif + static InsetMathHull * lastformula = 0; + static CursorBase current = DocIterator(ibegin(nucleus())); + static MathArray ar; + static string laststr; + + if (lastformula != this || laststr != str) { + //lyxerr << "reset lastformula to " << this << endl; + lastformula = this; + laststr = str; + current = ibegin(nucleus()); + ar.clear(); + mathed_parse_cell(ar, str); + } else { + increment(current); + } + //lyxerr << "searching '" << str << "' in " << this << ar << endl; + + for (DocIterator it = current; it != iend(nucleus()); increment(it)) { + CursorSlice & top = it.back(); + MathArray const & a = top.asInsetMath()->cell(top.idx_); + if (a.matchpart(ar, top.pos_)) { + bv->cursor().setSelection(it, ar.size()); + current = it; + top.pos_ += ar.size(); + bv->update(); + return true; + } + } + + //lyxerr << "not found!" << endl; + lastformula = 0; + return false; +} +#endif + + +void InsetMathHull::write(Buffer const &, std::ostream & os) const +{ + odocstringstream oss; + WriteStream wi(oss, false, false); + oss << "Formula "; + write(wi); + os << to_utf8(oss.str()); +} + + +void InsetMathHull::read(Buffer const &, LyXLex & lex) +{ + MathAtom at; + mathed_parse_normal(at, lex); + operator=(*at->asHullInset()); +} + + +int InsetMathHull::plaintext(Buffer const &, odocstream & os, + OutputParams const &) const +{ + if (0 && display()) { + Dimension dim; + TextMetricsInfo mi; + metricsT(mi, dim); + TextPainter tpain(dim.width(), dim.height()); + drawT(tpain, 0, dim.ascent()); + tpain.show(os, 3); + // reset metrics cache to "real" values + //metrics(); + return tpain.textheight(); + } else { + odocstringstream oss; + WriteStream wi(oss, false, true); + wi << cell(0); + + docstring const str = oss.str(); + os << str; + return str.size(); + } +} + + +int InsetMathHull::docbook(Buffer const & buf, odocstream & os, + OutputParams const & runparams) const +{ + MathStream ms(os); + int res = 0; + docstring name; + if (getType() == hullSimple) + name = from_ascii("inlineequation"); + else + name = from_ascii("informalequation"); + + docstring bname = name; + if (!label(0).empty()) + bname += " id='" + sgml::cleanID(buf, runparams, label(0)) + "'"; + ms << MTag(bname); + + odocstringstream ls; + if (runparams.flavor == OutputParams::XML) { + ms << MTag(from_ascii("alt role='tex' ")); + // Workaround for db2latex: db2latex always includes equations with + // \ensuremath{} or \begin{display}\end{display} + // so we strip LyX' math environment + WriteStream wi(ls, false, false); + InsetMathGrid::write(wi); + ms << from_utf8(subst(subst(to_utf8(ls.str()), "&", "&"), "<", "<")); + ms << ETag(from_ascii("alt")); + ms << MTag(from_ascii("math")); + ms << ETag(from_ascii("alt")); + ms << MTag(from_ascii("math")); + InsetMathGrid::mathmlize(ms); + ms << ETag(from_ascii("math")); + } else { + ms << MTag(from_ascii("alt role='tex'")); + res = latex(buf, ls, runparams); + ms << from_utf8(subst(subst(to_utf8(ls.str()), "&", "&"), "<", "<")); + ms << ETag(from_ascii("alt")); + } + + ms << from_ascii(""); + else + ms << from_ascii("\">"); + + ms << ETag(name); + return ms.line() + res; +} + + +void InsetMathHull::textString(Buffer const & buf, odocstream & os) const +{ + plaintext(buf, os, OutputParams(0)); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathKern.C b/src/mathed/InsetMathKern.C deleted file mode 100644 index c5cab3ec30..0000000000 --- a/src/mathed/InsetMathKern.C +++ /dev/null @@ -1,82 +0,0 @@ -/** - * \file InsetMathKern.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathKern.h" -#include "MathStream.h" -#include "MathStream.h" -#include "MathSupport.h" -#include "dimension.h" - - -namespace lyx { - -using std::string; -using std::auto_ptr; - - -InsetMathKern::InsetMathKern() -{ - dim_.asc = 0; - dim_.des = 0; -} - - -InsetMathKern::InsetMathKern(LyXLength const & w) - : wid_(w) -{ - dim_.asc = 0; - dim_.des = 0; -} - - -InsetMathKern::InsetMathKern(docstring const & s) - : wid_(to_utf8(s)) -{ - dim_.asc = 0; - dim_.des = 0; -} - - -auto_ptr InsetMathKern::doClone() const -{ - return auto_ptr(new InsetMathKern(*this)); -} - - -bool InsetMathKern::metrics(MetricsInfo & mi, Dimension & dim) const -{ - int wid_pixel = wid_.inPixels(0, mathed_char_width(mi.base.font, 'M')); - if (wid_pixel == dim_.wid) - return false; - dim_.wid = wid_pixel; - dim = dim_; - return true; -} - - -void InsetMathKern::draw(PainterInfo &, int, int) const -{} - - -void InsetMathKern::write(WriteStream & os) const -{ - os << "\\kern" << from_utf8(wid_.asLatexString()) << ' '; -} - - -void InsetMathKern::normalize(NormalStream & os) const -{ - os << "[kern " << from_utf8(wid_.asLatexString()) << ']'; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathKern.cpp b/src/mathed/InsetMathKern.cpp new file mode 100644 index 0000000000..c5cab3ec30 --- /dev/null +++ b/src/mathed/InsetMathKern.cpp @@ -0,0 +1,82 @@ +/** + * \file InsetMathKern.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathKern.h" +#include "MathStream.h" +#include "MathStream.h" +#include "MathSupport.h" +#include "dimension.h" + + +namespace lyx { + +using std::string; +using std::auto_ptr; + + +InsetMathKern::InsetMathKern() +{ + dim_.asc = 0; + dim_.des = 0; +} + + +InsetMathKern::InsetMathKern(LyXLength const & w) + : wid_(w) +{ + dim_.asc = 0; + dim_.des = 0; +} + + +InsetMathKern::InsetMathKern(docstring const & s) + : wid_(to_utf8(s)) +{ + dim_.asc = 0; + dim_.des = 0; +} + + +auto_ptr InsetMathKern::doClone() const +{ + return auto_ptr(new InsetMathKern(*this)); +} + + +bool InsetMathKern::metrics(MetricsInfo & mi, Dimension & dim) const +{ + int wid_pixel = wid_.inPixels(0, mathed_char_width(mi.base.font, 'M')); + if (wid_pixel == dim_.wid) + return false; + dim_.wid = wid_pixel; + dim = dim_; + return true; +} + + +void InsetMathKern::draw(PainterInfo &, int, int) const +{} + + +void InsetMathKern::write(WriteStream & os) const +{ + os << "\\kern" << from_utf8(wid_.asLatexString()) << ' '; +} + + +void InsetMathKern::normalize(NormalStream & os) const +{ + os << "[kern " << from_utf8(wid_.asLatexString()) << ']'; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathLefteqn.C b/src/mathed/InsetMathLefteqn.C deleted file mode 100644 index 4122d781f9..0000000000 --- a/src/mathed/InsetMathLefteqn.C +++ /dev/null @@ -1,69 +0,0 @@ -/** - * \file InsetMathLefteqn.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathLefteqn.h" -#include "MathData.h" -#include "support/std_ostream.h" - - -namespace lyx { - - -using std::string; -using std::auto_ptr; - - -InsetMathLefteqn::InsetMathLefteqn() - : InsetMathNest(1) -{} - - -auto_ptr InsetMathLefteqn::doClone() const -{ - return auto_ptr(new InsetMathLefteqn(*this)); -} - - -bool InsetMathLefteqn::metrics(MetricsInfo & mi, Dimension & dim) const -{ - cell(0).metrics(mi, dim); - dim.asc += 2; - dim.des += 2; - dim.wid = 4; - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathLefteqn::draw(PainterInfo & pi, int x, int y) const -{ - cell(0).draw(pi, x + 2, y); - drawMarkers(pi, x, y); -} - - -docstring InsetMathLefteqn::name() const -{ - return from_ascii("lefteqn"); -} - - -void InsetMathLefteqn::infoize(odocstream & os) const -{ - os << "Lefteqn "; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathLefteqn.cpp b/src/mathed/InsetMathLefteqn.cpp new file mode 100644 index 0000000000..4122d781f9 --- /dev/null +++ b/src/mathed/InsetMathLefteqn.cpp @@ -0,0 +1,69 @@ +/** + * \file InsetMathLefteqn.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathLefteqn.h" +#include "MathData.h" +#include "support/std_ostream.h" + + +namespace lyx { + + +using std::string; +using std::auto_ptr; + + +InsetMathLefteqn::InsetMathLefteqn() + : InsetMathNest(1) +{} + + +auto_ptr InsetMathLefteqn::doClone() const +{ + return auto_ptr(new InsetMathLefteqn(*this)); +} + + +bool InsetMathLefteqn::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(0).metrics(mi, dim); + dim.asc += 2; + dim.des += 2; + dim.wid = 4; + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathLefteqn::draw(PainterInfo & pi, int x, int y) const +{ + cell(0).draw(pi, x + 2, y); + drawMarkers(pi, x, y); +} + + +docstring InsetMathLefteqn::name() const +{ + return from_ascii("lefteqn"); +} + + +void InsetMathLefteqn::infoize(odocstream & os) const +{ + os << "Lefteqn "; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathLim.C b/src/mathed/InsetMathLim.C deleted file mode 100644 index ed333d933b..0000000000 --- a/src/mathed/InsetMathLim.C +++ /dev/null @@ -1,90 +0,0 @@ -/** - * \file InsetMathLim.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathLim.h" -#include "MathData.h" -#include "MathStream.h" -#include "debug.h" - - -namespace lyx { - -using std::auto_ptr; -using std::endl; - - -InsetMathLim::InsetMathLim - (MathArray const & f, MathArray const & x, MathArray const & x0) - : InsetMathNest(3) -{ - cell(0) = f; - cell(1) = x; - cell(2) = x0; -} - - -auto_ptr InsetMathLim::doClone() const -{ - return auto_ptr(new InsetMathLim(*this)); -} - - -void InsetMathLim::normalize(NormalStream & os) const -{ - os << "[lim " << cell(0) << ' ' << cell(1) << ' ' << cell(2) << ']'; -} - - -bool InsetMathLim::metrics(MetricsInfo &, Dimension &) const -{ - lyxerr << "should not happen" << endl; - return true; -} - - -void InsetMathLim::draw(PainterInfo &, int, int) const -{ - lyxerr << "should not happen" << endl; -} - - -void InsetMathLim::maple(MapleStream & os) const -{ - os << "limit(" << cell(0) << ',' << cell(1) << '=' << cell(2) << ')'; -} - - -void InsetMathLim::maxima(MaximaStream & os) const -{ - os << "limit(" << cell(0) << ',' << cell(1) << ',' << cell(2) << ')'; -} - - -void InsetMathLim::mathematica(MathematicaStream & os) const -{ - os << "Limit[" << cell(0) << ',' << cell(1) << "-> " << cell(2) << ']'; -} - - -void InsetMathLim::mathmlize(MathStream & os) const -{ - os << "lim(" << cell(0) << ',' << cell(1) << ',' << cell(2) << ')'; -} - - -void InsetMathLim::write(WriteStream &) const -{ - lyxerr << "should not happen" << endl; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathLim.cpp b/src/mathed/InsetMathLim.cpp new file mode 100644 index 0000000000..ed333d933b --- /dev/null +++ b/src/mathed/InsetMathLim.cpp @@ -0,0 +1,90 @@ +/** + * \file InsetMathLim.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathLim.h" +#include "MathData.h" +#include "MathStream.h" +#include "debug.h" + + +namespace lyx { + +using std::auto_ptr; +using std::endl; + + +InsetMathLim::InsetMathLim + (MathArray const & f, MathArray const & x, MathArray const & x0) + : InsetMathNest(3) +{ + cell(0) = f; + cell(1) = x; + cell(2) = x0; +} + + +auto_ptr InsetMathLim::doClone() const +{ + return auto_ptr(new InsetMathLim(*this)); +} + + +void InsetMathLim::normalize(NormalStream & os) const +{ + os << "[lim " << cell(0) << ' ' << cell(1) << ' ' << cell(2) << ']'; +} + + +bool InsetMathLim::metrics(MetricsInfo &, Dimension &) const +{ + lyxerr << "should not happen" << endl; + return true; +} + + +void InsetMathLim::draw(PainterInfo &, int, int) const +{ + lyxerr << "should not happen" << endl; +} + + +void InsetMathLim::maple(MapleStream & os) const +{ + os << "limit(" << cell(0) << ',' << cell(1) << '=' << cell(2) << ')'; +} + + +void InsetMathLim::maxima(MaximaStream & os) const +{ + os << "limit(" << cell(0) << ',' << cell(1) << ',' << cell(2) << ')'; +} + + +void InsetMathLim::mathematica(MathematicaStream & os) const +{ + os << "Limit[" << cell(0) << ',' << cell(1) << "-> " << cell(2) << ']'; +} + + +void InsetMathLim::mathmlize(MathStream & os) const +{ + os << "lim(" << cell(0) << ',' << cell(1) << ',' << cell(2) << ')'; +} + + +void InsetMathLim::write(WriteStream &) const +{ + lyxerr << "should not happen" << endl; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathMBox.C b/src/mathed/InsetMathMBox.C deleted file mode 100644 index 875f9f8447..0000000000 --- a/src/mathed/InsetMathMBox.C +++ /dev/null @@ -1,133 +0,0 @@ -/** - * \file InsetMathMBox.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathMBox.h" -#include "MathData.h" -#include "MathStream.h" - -#include "BufferView.h" -#include "buffer.h" -#include "bufferparams.h" -#include "cursor.h" -#include "debug.h" -#include "metricsinfo.h" -#include "output_latex.h" -#include "outputparams.h" -#include "paragraph.h" -#include "texrow.h" -#include "TextMetrics.h" - -namespace lyx { - -//using support::odocstream; - -using std::auto_ptr; -using std::endl; - - -InsetMathMBox::InsetMathMBox() -{ - text_.paragraphs().clear(); - text_.paragraphs().push_back(Paragraph()); -} - - -InsetMathMBox::InsetMathMBox(LyXLayout_ptr const & layout) -{ - text_.paragraphs().clear(); - text_.paragraphs().push_back(Paragraph()); - text_.paragraphs().back().layout(layout); -} - - -auto_ptr InsetMathMBox::doClone() const -{ - return auto_ptr(new InsetMathMBox(*this)); -} - - -bool InsetMathMBox::metrics(MetricsInfo & mi, Dimension & dim) const -{ - TextMetrics & tm = mi.base.bv->textMetrics(&text_); - tm.metrics(mi, dim); - metricsMarkers2(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathMBox::draw(PainterInfo & pi, int x, int y) const -{ - text_.draw(pi, x + 1, y); - drawMarkers(pi, x, y); -} - - -void InsetMathMBox::write(Buffer const & buf, WriteStream & ws) const -{ - if (ws.latex()) { - ws << "\\mbox{\n"; - TexRow texrow; - OutputParams runparams(&buf.params().encoding()); - latexParagraphs(buf, text_.paragraphs(), ws.os(), texrow, runparams); - ws.addlines(texrow.rows()); - ws << "}"; - } else { - ws << "\\mbox{\n"; - std::ostringstream os; - text_.write(buf, os); - ws.os() << from_utf8(os.str()); - ws << "}"; - } -} - - -int InsetMathMBox::latex(Buffer const & buf, odocstream & os, - OutputParams const & runparams) const -{ - os << "\\mbox{\n"; - TexRow texrow; - latexParagraphs(buf, text_.paragraphs(), os, texrow, runparams); - os << "}"; - return texrow.rows(); -} - - -void InsetMathMBox::doDispatch(LCursor & cur, FuncRequest & cmd) -{ - text_.dispatch(cur, cmd); -} - - -LyXText * InsetMathMBox::getText(int) const -{ - return &text_; -} - - -void InsetMathMBox::cursorPos(BufferView const & bv, - CursorSlice const & sl, bool boundary, int & x, int & y) const -{ - x = text_.cursorX(bv, sl, boundary); - y = text_.cursorY(bv, sl, boundary); -} - - -void InsetMathMBox::drawSelection(PainterInfo & pi, int x, int y) const -{ - text_.drawSelection(pi, x, y); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathMBox.cpp b/src/mathed/InsetMathMBox.cpp new file mode 100644 index 0000000000..875f9f8447 --- /dev/null +++ b/src/mathed/InsetMathMBox.cpp @@ -0,0 +1,133 @@ +/** + * \file InsetMathMBox.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathMBox.h" +#include "MathData.h" +#include "MathStream.h" + +#include "BufferView.h" +#include "buffer.h" +#include "bufferparams.h" +#include "cursor.h" +#include "debug.h" +#include "metricsinfo.h" +#include "output_latex.h" +#include "outputparams.h" +#include "paragraph.h" +#include "texrow.h" +#include "TextMetrics.h" + +namespace lyx { + +//using support::odocstream; + +using std::auto_ptr; +using std::endl; + + +InsetMathMBox::InsetMathMBox() +{ + text_.paragraphs().clear(); + text_.paragraphs().push_back(Paragraph()); +} + + +InsetMathMBox::InsetMathMBox(LyXLayout_ptr const & layout) +{ + text_.paragraphs().clear(); + text_.paragraphs().push_back(Paragraph()); + text_.paragraphs().back().layout(layout); +} + + +auto_ptr InsetMathMBox::doClone() const +{ + return auto_ptr(new InsetMathMBox(*this)); +} + + +bool InsetMathMBox::metrics(MetricsInfo & mi, Dimension & dim) const +{ + TextMetrics & tm = mi.base.bv->textMetrics(&text_); + tm.metrics(mi, dim); + metricsMarkers2(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathMBox::draw(PainterInfo & pi, int x, int y) const +{ + text_.draw(pi, x + 1, y); + drawMarkers(pi, x, y); +} + + +void InsetMathMBox::write(Buffer const & buf, WriteStream & ws) const +{ + if (ws.latex()) { + ws << "\\mbox{\n"; + TexRow texrow; + OutputParams runparams(&buf.params().encoding()); + latexParagraphs(buf, text_.paragraphs(), ws.os(), texrow, runparams); + ws.addlines(texrow.rows()); + ws << "}"; + } else { + ws << "\\mbox{\n"; + std::ostringstream os; + text_.write(buf, os); + ws.os() << from_utf8(os.str()); + ws << "}"; + } +} + + +int InsetMathMBox::latex(Buffer const & buf, odocstream & os, + OutputParams const & runparams) const +{ + os << "\\mbox{\n"; + TexRow texrow; + latexParagraphs(buf, text_.paragraphs(), os, texrow, runparams); + os << "}"; + return texrow.rows(); +} + + +void InsetMathMBox::doDispatch(LCursor & cur, FuncRequest & cmd) +{ + text_.dispatch(cur, cmd); +} + + +LyXText * InsetMathMBox::getText(int) const +{ + return &text_; +} + + +void InsetMathMBox::cursorPos(BufferView const & bv, + CursorSlice const & sl, bool boundary, int & x, int & y) const +{ + x = text_.cursorX(bv, sl, boundary); + y = text_.cursorY(bv, sl, boundary); +} + + +void InsetMathMBox::drawSelection(PainterInfo & pi, int x, int y) const +{ + text_.drawSelection(pi, x, y); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathMacro.C b/src/mathed/InsetMathMacro.C deleted file mode 100644 index 27b868c4a3..0000000000 --- a/src/mathed/InsetMathMacro.C +++ /dev/null @@ -1,290 +0,0 @@ -/** - * \file InsetMathMacro.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Alejandro Aguilar Sierra - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathMacro.h" -#include "MathSupport.h" -#include "MathExtern.h" -#include "MathStream.h" - -#include "buffer.h" -#include "cursor.h" -#include "debug.h" -#include "BufferView.h" -#include "LaTeXFeatures.h" -#include "frontends/Painter.h" - - -namespace lyx { - -using std::string; -using std::max; -using std::auto_ptr; -using std::endl; -using std::vector; - - -/// This class is the value of a macro argument, technically -/// a wrapper of the cells of MathMacro. -class MathMacroArgumentValue : public InsetMathDim { -public: - /// - MathMacroArgumentValue(MathArray const * value, docstring const & macroName) - : value_(value), macroName_(macroName) {} - /// - bool metrics(MetricsInfo & mi, Dimension & dim) const; - /// - void draw(PainterInfo &, int x, int y) const; - -private: - std::auto_ptr doClone() const; - MathArray const * value_; - docstring macroName_; -}; - - -auto_ptr MathMacroArgumentValue::doClone() const -{ - return auto_ptr(new MathMacroArgumentValue(*this)); -} - - -bool MathMacroArgumentValue::metrics(MetricsInfo & mi, Dimension & dim) const -{ - // unlock outer macro in arguments, and lock it again later - MacroTable::globalMacros().get(macroName_).unlock(); - value_->metrics(mi, dim); - MacroTable::globalMacros().get(macroName_).lock(); - metricsMarkers2(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void MathMacroArgumentValue::draw(PainterInfo & pi, int x, int y) const -{ - // unlock outer macro in arguments, and lock it again later - MacroTable::globalMacros().get(macroName_).unlock(); - value_->draw(pi, x, y); - MacroTable::globalMacros().get(macroName_).lock(); -} - - -MathMacro::MathMacro(docstring const & name, int numargs) - : InsetMathNest(numargs), name_(name) -{} - - -auto_ptr MathMacro::doClone() const -{ - return auto_ptr(new MathMacro(*this)); -} - - -docstring MathMacro::name() const -{ - return name_; -} - - -void MathMacro::cursorPos(BufferView const & bv, - CursorSlice const & sl, bool boundary, int & x, int & y) const -{ - // We may have 0 arguments, but InsetMathNest requires at least one. - if (nargs() > 0) - InsetMathNest::cursorPos(bv, sl, boundary, x, y); -} - - -bool MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const -{ - if (!MacroTable::globalMacros().has(name())) { - mathed_string_dim(mi.base.font, "Unknown: " + name(), dim); - } else { - MacroData const & macro = MacroTable::globalMacros().get(name()); - if (macro.locked()) { - mathed_string_dim(mi.base.font, "Self reference: " + name(), dim); - expanded_ = MathArray(); - } else if (editing(mi.base.bv)) { - // FIXME UNICODE - asArray(macro.def(), tmpl_); - LyXFont font = mi.base.font; - augmentFont(font, from_ascii("lyxtex")); - tmpl_.metrics(mi, dim); - // FIXME UNICODE - dim.wid += mathed_string_width(font, name()) + 10; - // FIXME UNICODE - int ww = mathed_string_width(font, from_ascii("#1: ")); - for (idx_type i = 0; i < nargs(); ++i) { - MathArray const & c = cell(i); - c.metrics(mi); - dim.wid = max(dim.wid, c.width() + ww); - dim.des += c.height() + 10; - } - } else { - // create MathMacroArgumentValue object pointing to the cells of the macro - MacroData const & macro = MacroTable::globalMacros().get(name()); - vector values(nargs()); - for (size_t i = 0; i != nargs(); ++i) - values[i].insert(0, MathAtom(new MathMacroArgumentValue(&cells_[i], name()))); - macro.expand(values, expanded_); - - MacroTable::globalMacros().get(name()).lock(); - expanded_.metrics(mi, dim); - MacroTable::globalMacros().get(name()).unlock(); - } - } - metricsMarkers2(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void MathMacro::draw(PainterInfo & pi, int x, int y) const -{ - if (!MacroTable::globalMacros().has(name())) { - // FIXME UNICODE - drawStrRed(pi, x, y, "Unknown: " + name()); - } else { - MacroData const & macro = MacroTable::globalMacros().get(name()); - if (macro.locked()) { - // FIXME UNICODE - drawStrRed(pi, x, y, "Self reference: " + name()); - } else if (editing(pi.base.bv)) { - LyXFont font = pi.base.font; - augmentFont(font, from_ascii("lyxtex")); - int h = y - dim_.ascent() + 2 + tmpl_.ascent(); - pi.pain.text(x + 3, h, name(), font); - int const w = mathed_string_width(font, name()); - tmpl_.draw(pi, x + w + 12, h); - h += tmpl_.descent(); - Dimension ldim; - docstring t = from_ascii("#1: "); - mathed_string_dim(font, t, ldim); - for (idx_type i = 0; i < nargs(); ++i) { - MathArray const & c = cell(i); - h += max(c.ascent(), ldim.asc) + 5; - c.draw(pi, x + ldim.wid, h); - char_type str[] = { '#', '1', ':', '\0' }; - str[1] += static_cast(i); - pi.pain.text(x + 3, h, str, font); - h += max(c.descent(), ldim.des) + 5; - } - } else { - MacroTable::globalMacros().get(name()).lock(); - expanded_.draw(pi, x, y); - MacroTable::globalMacros().get(name()).unlock(); - } - } - drawMarkers2(pi, x, y); -} - - -void MathMacro::drawSelection(PainterInfo & pi, int x, int y) const -{ - // We may have 0 arguments, but InsetMathNest requires at least one. - if (nargs() > 0) - InsetMathNest::drawSelection(pi, x, y); -} - - -void MathMacro::validate(LaTeXFeatures & features) const -{ - if (name() == "binom" || name() == "mathcircumflex") - features.require(to_utf8(name())); -} - - -InsetBase * MathMacro::editXY(LCursor & cur, int x, int y) -{ - // We may have 0 arguments, but InsetMathNest requires at least one. - if (nargs() > 0) { - // Prevent crash due to cold coordcache - // FIXME: This is only a workaround, the call of - // InsetMathNest::editXY is correct. The correct fix would - // ensure that the coordcache of the arguments is valid. - if (!editing(&cur.bv())) { - edit(cur, true); - return this; - } - return InsetMathNest::editXY(cur, x, y); - } - return this; -} - - -bool MathMacro::idxFirst(LCursor & cur) const -{ - cur.updateFlags(Update::Force); - return InsetMathNest::idxFirst(cur); -} - - -bool MathMacro::idxLast(LCursor & cur) const -{ - cur.updateFlags(Update::Force); - return InsetMathNest::idxLast(cur); -} - - -bool MathMacro::notifyCursorLeaves(LCursor & cur) -{ - cur.updateFlags(Update::Force); - return InsetMathNest::notifyCursorLeaves(cur); -} - - -void MathMacro::maple(MapleStream & os) const -{ - updateExpansion(); - lyx::maple(expanded_, os); -} - - -void MathMacro::mathmlize(MathStream & os) const -{ - updateExpansion(); - lyx::mathmlize(expanded_, os); -} - - -void MathMacro::octave(OctaveStream & os) const -{ - updateExpansion(); - lyx::octave(expanded_, os); -} - - -void MathMacro::updateExpansion() const -{ - //expanded_.substitute(*this); -} - - -void MathMacro::infoize(odocstream & os) const -{ - os << "Macro: " << name(); -} - - -void MathMacro::infoize2(odocstream & os) const -{ - os << "Macro: " << name(); - -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathMacro.cpp b/src/mathed/InsetMathMacro.cpp new file mode 100644 index 0000000000..27b868c4a3 --- /dev/null +++ b/src/mathed/InsetMathMacro.cpp @@ -0,0 +1,290 @@ +/** + * \file InsetMathMacro.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Alejandro Aguilar Sierra + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathMacro.h" +#include "MathSupport.h" +#include "MathExtern.h" +#include "MathStream.h" + +#include "buffer.h" +#include "cursor.h" +#include "debug.h" +#include "BufferView.h" +#include "LaTeXFeatures.h" +#include "frontends/Painter.h" + + +namespace lyx { + +using std::string; +using std::max; +using std::auto_ptr; +using std::endl; +using std::vector; + + +/// This class is the value of a macro argument, technically +/// a wrapper of the cells of MathMacro. +class MathMacroArgumentValue : public InsetMathDim { +public: + /// + MathMacroArgumentValue(MathArray const * value, docstring const & macroName) + : value_(value), macroName_(macroName) {} + /// + bool metrics(MetricsInfo & mi, Dimension & dim) const; + /// + void draw(PainterInfo &, int x, int y) const; + +private: + std::auto_ptr doClone() const; + MathArray const * value_; + docstring macroName_; +}; + + +auto_ptr MathMacroArgumentValue::doClone() const +{ + return auto_ptr(new MathMacroArgumentValue(*this)); +} + + +bool MathMacroArgumentValue::metrics(MetricsInfo & mi, Dimension & dim) const +{ + // unlock outer macro in arguments, and lock it again later + MacroTable::globalMacros().get(macroName_).unlock(); + value_->metrics(mi, dim); + MacroTable::globalMacros().get(macroName_).lock(); + metricsMarkers2(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void MathMacroArgumentValue::draw(PainterInfo & pi, int x, int y) const +{ + // unlock outer macro in arguments, and lock it again later + MacroTable::globalMacros().get(macroName_).unlock(); + value_->draw(pi, x, y); + MacroTable::globalMacros().get(macroName_).lock(); +} + + +MathMacro::MathMacro(docstring const & name, int numargs) + : InsetMathNest(numargs), name_(name) +{} + + +auto_ptr MathMacro::doClone() const +{ + return auto_ptr(new MathMacro(*this)); +} + + +docstring MathMacro::name() const +{ + return name_; +} + + +void MathMacro::cursorPos(BufferView const & bv, + CursorSlice const & sl, bool boundary, int & x, int & y) const +{ + // We may have 0 arguments, but InsetMathNest requires at least one. + if (nargs() > 0) + InsetMathNest::cursorPos(bv, sl, boundary, x, y); +} + + +bool MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const +{ + if (!MacroTable::globalMacros().has(name())) { + mathed_string_dim(mi.base.font, "Unknown: " + name(), dim); + } else { + MacroData const & macro = MacroTable::globalMacros().get(name()); + if (macro.locked()) { + mathed_string_dim(mi.base.font, "Self reference: " + name(), dim); + expanded_ = MathArray(); + } else if (editing(mi.base.bv)) { + // FIXME UNICODE + asArray(macro.def(), tmpl_); + LyXFont font = mi.base.font; + augmentFont(font, from_ascii("lyxtex")); + tmpl_.metrics(mi, dim); + // FIXME UNICODE + dim.wid += mathed_string_width(font, name()) + 10; + // FIXME UNICODE + int ww = mathed_string_width(font, from_ascii("#1: ")); + for (idx_type i = 0; i < nargs(); ++i) { + MathArray const & c = cell(i); + c.metrics(mi); + dim.wid = max(dim.wid, c.width() + ww); + dim.des += c.height() + 10; + } + } else { + // create MathMacroArgumentValue object pointing to the cells of the macro + MacroData const & macro = MacroTable::globalMacros().get(name()); + vector values(nargs()); + for (size_t i = 0; i != nargs(); ++i) + values[i].insert(0, MathAtom(new MathMacroArgumentValue(&cells_[i], name()))); + macro.expand(values, expanded_); + + MacroTable::globalMacros().get(name()).lock(); + expanded_.metrics(mi, dim); + MacroTable::globalMacros().get(name()).unlock(); + } + } + metricsMarkers2(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void MathMacro::draw(PainterInfo & pi, int x, int y) const +{ + if (!MacroTable::globalMacros().has(name())) { + // FIXME UNICODE + drawStrRed(pi, x, y, "Unknown: " + name()); + } else { + MacroData const & macro = MacroTable::globalMacros().get(name()); + if (macro.locked()) { + // FIXME UNICODE + drawStrRed(pi, x, y, "Self reference: " + name()); + } else if (editing(pi.base.bv)) { + LyXFont font = pi.base.font; + augmentFont(font, from_ascii("lyxtex")); + int h = y - dim_.ascent() + 2 + tmpl_.ascent(); + pi.pain.text(x + 3, h, name(), font); + int const w = mathed_string_width(font, name()); + tmpl_.draw(pi, x + w + 12, h); + h += tmpl_.descent(); + Dimension ldim; + docstring t = from_ascii("#1: "); + mathed_string_dim(font, t, ldim); + for (idx_type i = 0; i < nargs(); ++i) { + MathArray const & c = cell(i); + h += max(c.ascent(), ldim.asc) + 5; + c.draw(pi, x + ldim.wid, h); + char_type str[] = { '#', '1', ':', '\0' }; + str[1] += static_cast(i); + pi.pain.text(x + 3, h, str, font); + h += max(c.descent(), ldim.des) + 5; + } + } else { + MacroTable::globalMacros().get(name()).lock(); + expanded_.draw(pi, x, y); + MacroTable::globalMacros().get(name()).unlock(); + } + } + drawMarkers2(pi, x, y); +} + + +void MathMacro::drawSelection(PainterInfo & pi, int x, int y) const +{ + // We may have 0 arguments, but InsetMathNest requires at least one. + if (nargs() > 0) + InsetMathNest::drawSelection(pi, x, y); +} + + +void MathMacro::validate(LaTeXFeatures & features) const +{ + if (name() == "binom" || name() == "mathcircumflex") + features.require(to_utf8(name())); +} + + +InsetBase * MathMacro::editXY(LCursor & cur, int x, int y) +{ + // We may have 0 arguments, but InsetMathNest requires at least one. + if (nargs() > 0) { + // Prevent crash due to cold coordcache + // FIXME: This is only a workaround, the call of + // InsetMathNest::editXY is correct. The correct fix would + // ensure that the coordcache of the arguments is valid. + if (!editing(&cur.bv())) { + edit(cur, true); + return this; + } + return InsetMathNest::editXY(cur, x, y); + } + return this; +} + + +bool MathMacro::idxFirst(LCursor & cur) const +{ + cur.updateFlags(Update::Force); + return InsetMathNest::idxFirst(cur); +} + + +bool MathMacro::idxLast(LCursor & cur) const +{ + cur.updateFlags(Update::Force); + return InsetMathNest::idxLast(cur); +} + + +bool MathMacro::notifyCursorLeaves(LCursor & cur) +{ + cur.updateFlags(Update::Force); + return InsetMathNest::notifyCursorLeaves(cur); +} + + +void MathMacro::maple(MapleStream & os) const +{ + updateExpansion(); + lyx::maple(expanded_, os); +} + + +void MathMacro::mathmlize(MathStream & os) const +{ + updateExpansion(); + lyx::mathmlize(expanded_, os); +} + + +void MathMacro::octave(OctaveStream & os) const +{ + updateExpansion(); + lyx::octave(expanded_, os); +} + + +void MathMacro::updateExpansion() const +{ + //expanded_.substitute(*this); +} + + +void MathMacro::infoize(odocstream & os) const +{ + os << "Macro: " << name(); +} + + +void MathMacro::infoize2(odocstream & os) const +{ + os << "Macro: " << name(); + +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathMakebox.C b/src/mathed/InsetMathMakebox.C deleted file mode 100644 index fb6a0b09a4..0000000000 --- a/src/mathed/InsetMathMakebox.C +++ /dev/null @@ -1,101 +0,0 @@ -/** - * \file InsetMathMakebox.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Ling Li - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathMakebox.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathSupport.h" - -#include "support/std_ostream.h" - - -namespace lyx { - -using std::auto_ptr; - - -InsetMathMakebox::InsetMathMakebox() - : InsetMathNest(3) -{} - - -auto_ptr InsetMathMakebox::doClone() const -{ - return auto_ptr(new InsetMathMakebox(*this)); -} - - -bool InsetMathMakebox::metrics(MetricsInfo & mi, Dimension & dim) const -{ - FontSetChanger dummy(mi.base, from_ascii("textnormal")); - w_ = mathed_char_width(mi.base.font, '['); - InsetMathNest::metrics(mi); - dim = cell(0).dim(); - dim += cell(1).dim(); - dim += cell(2).dim(); - dim.wid += 4 * w_ + 4; - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathMakebox::draw(PainterInfo & pi, int x, int y) const -{ - FontSetChanger dummy(pi.base, from_ascii("textnormal")); - drawMarkers(pi, x, y); - - drawStrBlack(pi, x, y, from_ascii("[")); - x += w_; - cell(0).draw(pi, x, y); - x += cell(0).width(); - drawStrBlack(pi, x, y, from_ascii("]")); - x += w_ + 2; - - drawStrBlack(pi, x, y, from_ascii("[")); - x += w_; - cell(1).draw(pi, x, y); - x += cell(1).width(); - drawStrBlack(pi, x, y, from_ascii("]")); - x += w_ + 2; - - cell(2).draw(pi, x, y); - setPosCache(pi, x, y); -} - - -void InsetMathMakebox::write(WriteStream & os) const -{ - os << "\\makebox"; - os << '[' << cell(0) << ']'; - if (cell(1).size()) - os << '[' << cell(1) << ']'; - os << '{' << cell(2) << '}'; -} - - -void InsetMathMakebox::normalize(NormalStream & os) const -{ - os << "[makebox " << cell(0) << ' ' << cell(1) << ' ' << cell(2) << ']'; -} - - -void InsetMathMakebox::infoize(odocstream & os) const -{ - os << "Makebox (width: " << cell(0) - << " pos: " << cell(1) << ")"; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathMakebox.cpp b/src/mathed/InsetMathMakebox.cpp new file mode 100644 index 0000000000..fb6a0b09a4 --- /dev/null +++ b/src/mathed/InsetMathMakebox.cpp @@ -0,0 +1,101 @@ +/** + * \file InsetMathMakebox.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Ling Li + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathMakebox.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathSupport.h" + +#include "support/std_ostream.h" + + +namespace lyx { + +using std::auto_ptr; + + +InsetMathMakebox::InsetMathMakebox() + : InsetMathNest(3) +{} + + +auto_ptr InsetMathMakebox::doClone() const +{ + return auto_ptr(new InsetMathMakebox(*this)); +} + + +bool InsetMathMakebox::metrics(MetricsInfo & mi, Dimension & dim) const +{ + FontSetChanger dummy(mi.base, from_ascii("textnormal")); + w_ = mathed_char_width(mi.base.font, '['); + InsetMathNest::metrics(mi); + dim = cell(0).dim(); + dim += cell(1).dim(); + dim += cell(2).dim(); + dim.wid += 4 * w_ + 4; + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathMakebox::draw(PainterInfo & pi, int x, int y) const +{ + FontSetChanger dummy(pi.base, from_ascii("textnormal")); + drawMarkers(pi, x, y); + + drawStrBlack(pi, x, y, from_ascii("[")); + x += w_; + cell(0).draw(pi, x, y); + x += cell(0).width(); + drawStrBlack(pi, x, y, from_ascii("]")); + x += w_ + 2; + + drawStrBlack(pi, x, y, from_ascii("[")); + x += w_; + cell(1).draw(pi, x, y); + x += cell(1).width(); + drawStrBlack(pi, x, y, from_ascii("]")); + x += w_ + 2; + + cell(2).draw(pi, x, y); + setPosCache(pi, x, y); +} + + +void InsetMathMakebox::write(WriteStream & os) const +{ + os << "\\makebox"; + os << '[' << cell(0) << ']'; + if (cell(1).size()) + os << '[' << cell(1) << ']'; + os << '{' << cell(2) << '}'; +} + + +void InsetMathMakebox::normalize(NormalStream & os) const +{ + os << "[makebox " << cell(0) << ' ' << cell(1) << ' ' << cell(2) << ']'; +} + + +void InsetMathMakebox::infoize(odocstream & os) const +{ + os << "Makebox (width: " << cell(0) + << " pos: " << cell(1) << ")"; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathMatrix.C b/src/mathed/InsetMathMatrix.C deleted file mode 100644 index feb56cb3df..0000000000 --- a/src/mathed/InsetMathMatrix.C +++ /dev/null @@ -1,115 +0,0 @@ -/** - * \file InsetMathMatrix.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathMatrix.h" -#include "MathData.h" -#include "MathStream.h" - - -namespace lyx { - -using std::auto_ptr; - - -InsetMathMatrix::InsetMathMatrix(InsetMathGrid const & p) - : InsetMathGrid(p) -{} - - -auto_ptr InsetMathMatrix::doClone() const -{ - return auto_ptr(new InsetMathMatrix(*this)); -} - - -void InsetMathMatrix::write(WriteStream & os) const -{ - InsetMathGrid::write(os); -} - - -void InsetMathMatrix::normalize(NormalStream & os) const -{ - InsetMathGrid::normalize(os); -} - - -void InsetMathMatrix::maple(MapleStream & os) const -{ - os << "matrix(" << int(nrows()) << ',' << int(ncols()) << ",["; - for (idx_type idx = 0; idx < nargs(); ++idx) { - if (idx) - os << ','; - os << cell(idx); - } - os << "])"; -} - - -void InsetMathMatrix::maxima(MaximaStream & os) const -{ - os << "matrix("; - for (row_type row = 0; row < nrows(); ++row) { - if (row) - os << ','; - os << '['; - for (col_type col = 0; col < ncols(); ++col) { - if (col) - os << ','; - os << cell(index(row, col)); - } - os << ']'; - } - os << ')'; -} - - -void InsetMathMatrix::mathematica(MathematicaStream & os) const -{ - os << '{'; - for (row_type row = 0; row < nrows(); ++row) { - if (row) - os << ','; - os << '{'; - for (col_type col = 0; col < ncols(); ++col) { - if (col) - os << ','; - os << cell(index(row, col)); - } - os << '}'; - } - os << '}'; -} - - -void InsetMathMatrix::mathmlize(MathStream & os) const -{ - InsetMathGrid::mathmlize(os); -} - - -void InsetMathMatrix::octave(OctaveStream & os) const -{ - os << '['; - for (row_type row = 0; row < nrows(); ++row) { - if (row) - os << ';'; - os << '['; - for (col_type col = 0; col < ncols(); ++col) - os << cell(index(row, col)) << ' '; - os << ']'; - } - os << ']'; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathMatrix.cpp b/src/mathed/InsetMathMatrix.cpp new file mode 100644 index 0000000000..feb56cb3df --- /dev/null +++ b/src/mathed/InsetMathMatrix.cpp @@ -0,0 +1,115 @@ +/** + * \file InsetMathMatrix.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathMatrix.h" +#include "MathData.h" +#include "MathStream.h" + + +namespace lyx { + +using std::auto_ptr; + + +InsetMathMatrix::InsetMathMatrix(InsetMathGrid const & p) + : InsetMathGrid(p) +{} + + +auto_ptr InsetMathMatrix::doClone() const +{ + return auto_ptr(new InsetMathMatrix(*this)); +} + + +void InsetMathMatrix::write(WriteStream & os) const +{ + InsetMathGrid::write(os); +} + + +void InsetMathMatrix::normalize(NormalStream & os) const +{ + InsetMathGrid::normalize(os); +} + + +void InsetMathMatrix::maple(MapleStream & os) const +{ + os << "matrix(" << int(nrows()) << ',' << int(ncols()) << ",["; + for (idx_type idx = 0; idx < nargs(); ++idx) { + if (idx) + os << ','; + os << cell(idx); + } + os << "])"; +} + + +void InsetMathMatrix::maxima(MaximaStream & os) const +{ + os << "matrix("; + for (row_type row = 0; row < nrows(); ++row) { + if (row) + os << ','; + os << '['; + for (col_type col = 0; col < ncols(); ++col) { + if (col) + os << ','; + os << cell(index(row, col)); + } + os << ']'; + } + os << ')'; +} + + +void InsetMathMatrix::mathematica(MathematicaStream & os) const +{ + os << '{'; + for (row_type row = 0; row < nrows(); ++row) { + if (row) + os << ','; + os << '{'; + for (col_type col = 0; col < ncols(); ++col) { + if (col) + os << ','; + os << cell(index(row, col)); + } + os << '}'; + } + os << '}'; +} + + +void InsetMathMatrix::mathmlize(MathStream & os) const +{ + InsetMathGrid::mathmlize(os); +} + + +void InsetMathMatrix::octave(OctaveStream & os) const +{ + os << '['; + for (row_type row = 0; row < nrows(); ++row) { + if (row) + os << ';'; + os << '['; + for (col_type col = 0; col < ncols(); ++col) + os << cell(index(row, col)) << ' '; + os << ']'; + } + os << ']'; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathNest.C b/src/mathed/InsetMathNest.C deleted file mode 100644 index 1d18ae086e..0000000000 --- a/src/mathed/InsetMathNest.C +++ /dev/null @@ -1,1469 +0,0 @@ -/** - * \file InsetMathNest.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathNest.h" - -#include "InsetMathArray.h" -#include "InsetMathBig.h" -#include "InsetMathBox.h" -#include "InsetMathBrace.h" -#include "InsetMathColor.h" -#include "InsetMathComment.h" -#include "MathData.h" -#include "InsetMathDelim.h" -#include "MathFactory.h" -#include "InsetMathHull.h" -#include "MathStream.h" -#include "MathMacroArgument.h" -//#include "InsetMathMBox.h" -#include "MathParser.h" -#include "InsetMathScript.h" -#include "InsetMathSpace.h" -#include "InsetMathSymbol.h" -#include "MathSupport.h" -#include "InsetMathUnknown.h" -#include "InsetMathRef.h" - -#include "BufferView.h" -#include "CutAndPaste.h" -#include "FuncStatus.h" -#include "LColor.h" -#include "bufferview_funcs.h" -#include "coordcache.h" -#include "cursor.h" -#include "debug.h" -#include "dispatchresult.h" -#include "funcrequest.h" -#include "gettext.h" -#include "lyxtext.h" -#include "outputparams.h" -#include "undo.h" - -#include "support/lstrings.h" -#include "support/textutils.h" - -#include "frontends/Clipboard.h" -#include "frontends/Painter.h" -#include "frontends/Selection.h" - -#include "funcrequest.h" -#include "lyxserver.h" -#include "lyxsocket.h" - -#include - - -namespace lyx { - -using cap::copySelection; -using cap::grabAndEraseSelection; -using cap::cutSelection; -using cap::replaceSelection; -using cap::selClearOrDel; - -using std::endl; -using std::string; -using std::istringstream; - - -InsetMathNest::InsetMathNest(idx_type nargs) - : cells_(nargs), lock_(false) -{} - - -InsetMath::idx_type InsetMathNest::nargs() const -{ - return cells_.size(); -} - - -void InsetMathNest::cursorPos(BufferView const & bv, - CursorSlice const & sl, bool /*boundary*/, - int & x, int & y) const -{ -// FIXME: This is a hack. Ideally, the coord cache should not store -// absolute positions, but relative ones. This would mean to call -// setXY() not in MathArray::draw(), but in the parent insets' draw() -// with the correctly adjusted x,y values. But this means that we'd have -// to touch all (math)inset's draw() methods. Right now, we'll store -// absolute value, and make them here relative, only to make them -// absolute again when actually drawing the cursor. What a mess. - BOOST_ASSERT(ptr_cmp(&sl.inset(), this)); - MathArray const & ar = sl.cell(); - CoordCache const & coord_cache = bv.coordCache(); - if (!coord_cache.getArrays().has(&ar)) { - // this can (semi-)legally happen if we just created this cell - // and it never has been drawn before. So don't ASSERT. - //lyxerr << "no cached data for array " << &ar << endl; - x = 0; - y = 0; - return; - } - Point const pt = coord_cache.getArrays().xy(&ar); - if (!coord_cache.getInsets().has(this)) { - // same as above - //lyxerr << "no cached data for inset " << this << endl; - x = 0; - y = 0; - return; - } - Point const pt2 = coord_cache.getInsets().xy(this); - //lyxerr << "retrieving position cache for MathArray " - // << pt.x_ << ' ' << pt.y_ << std::endl; - x = pt.x_ - pt2.x_ + ar.pos2x(sl.pos()); - y = pt.y_ - pt2.y_; -// lyxerr << "pt.y_ : " << pt.y_ << " pt2_.y_ : " << pt2.y_ -// << " asc: " << ascent() << " des: " << descent() -// << " ar.asc: " << ar.ascent() << " ar.des: " << ar.descent() << endl; - // move cursor visually into empty cells ("blue rectangles"); - if (ar.empty()) - x += 2; -} - - -void InsetMathNest::metrics(MetricsInfo const & mi) const -{ - MetricsInfo m = mi; - for (idx_type i = 0, n = nargs(); i != n; ++i) - cell(i).metrics(m); -} - - -bool InsetMathNest::idxNext(LCursor & cur) const -{ - BOOST_ASSERT(ptr_cmp(&cur.inset(), this)); - if (cur.idx() == cur.lastidx()) - return false; - ++cur.idx(); - cur.pos() = 0; - return true; -} - - -bool InsetMathNest::idxRight(LCursor & cur) const -{ - return idxNext(cur); -} - - -bool InsetMathNest::idxPrev(LCursor & cur) const -{ - BOOST_ASSERT(ptr_cmp(&cur.inset(), this)); - if (cur.idx() == 0) - return false; - --cur.idx(); - cur.pos() = cur.lastpos(); - return true; -} - - -bool InsetMathNest::idxLeft(LCursor & cur) const -{ - return idxPrev(cur); -} - - -bool InsetMathNest::idxFirst(LCursor & cur) const -{ - BOOST_ASSERT(ptr_cmp(&cur.inset(), this)); - if (nargs() == 0) - return false; - cur.idx() = 0; - cur.pos() = 0; - return true; -} - - -bool InsetMathNest::idxLast(LCursor & cur) const -{ - BOOST_ASSERT(ptr_cmp(&cur.inset(), this)); - if (nargs() == 0) - return false; - cur.idx() = cur.lastidx(); - cur.pos() = cur.lastpos(); - return true; -} - - -void InsetMathNest::dump() const -{ - odocstringstream oss; - WriteStream os(oss); - os << "---------------------------------------------\n"; - write(os); - os << "\n"; - for (idx_type i = 0, n = nargs(); i != n; ++i) - os << cell(i) << "\n"; - os << "---------------------------------------------\n"; - lyxerr << to_utf8(oss.str()); -} - - -void InsetMathNest::draw(PainterInfo & pi, int x, int y) const -{ -#if 0 - if (lock_) - pi.pain.fillRectangle(x, y - ascent(), width(), height(), - LColor::mathlockbg); -#endif - setPosCache(pi, x, y); -} - - -void InsetMathNest::drawSelection(PainterInfo & pi, int x, int y) const -{ - BufferView & bv = *pi.base.bv; - // this should use the x/y values given, not the cached values - LCursor & cur = bv.cursor(); - if (!cur.selection()) - return; - if (!ptr_cmp(&cur.inset(), this)) - return; - - // FIXME: hack to get position cache warm - pi.pain.setDrawingEnabled(false); - draw(pi, x, y); - pi.pain.setDrawingEnabled(true); - - CursorSlice s1 = cur.selBegin(); - CursorSlice s2 = cur.selEnd(); - - //lyxerr << "InsetMathNest::drawing selection: " - // << " s1: " << s1 << " s2: " << s2 << endl; - if (s1.idx() == s2.idx()) { - MathArray const & c = cell(s1.idx()); - int x1 = c.xo(bv) + c.pos2x(s1.pos()); - int y1 = c.yo(bv) - c.ascent(); - int x2 = c.xo(bv) + c.pos2x(s2.pos()); - int y2 = c.yo(bv) + c.descent(); - pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection); - //lyxerr << "InsetMathNest::drawing selection 3: " - // << " x1: " << x1 << " x2: " << x2 - // << " y1: " << y1 << " y2: " << y2 << endl; - } else { - for (idx_type i = 0; i < nargs(); ++i) { - if (idxBetween(i, s1.idx(), s2.idx())) { - MathArray const & c = cell(i); - int x1 = c.xo(bv); - int y1 = c.yo(bv) - c.ascent(); - int x2 = c.xo(bv) + c.width(); - int y2 = c.yo(bv) + c.descent(); - pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection); - } - } - } -} - - -void InsetMathNest::validate(LaTeXFeatures & features) const -{ - for (idx_type i = 0; i < nargs(); ++i) - cell(i).validate(features); -} - - -void InsetMathNest::replace(ReplaceData & rep) -{ - for (idx_type i = 0; i < nargs(); ++i) - cell(i).replace(rep); -} - - -bool InsetMathNest::contains(MathArray const & ar) const -{ - for (idx_type i = 0; i < nargs(); ++i) - if (cell(i).contains(ar)) - return true; - return false; -} - - -bool InsetMathNest::lock() const -{ - return lock_; -} - - -void InsetMathNest::lock(bool l) -{ - lock_ = l; -} - - -bool InsetMathNest::isActive() const -{ - return nargs() > 0; -} - - -MathArray InsetMathNest::glue() const -{ - MathArray ar; - for (size_t i = 0; i < nargs(); ++i) - ar.append(cell(i)); - return ar; -} - - -void InsetMathNest::write(WriteStream & os) const -{ - os << '\\' << name().c_str(); - for (size_t i = 0; i < nargs(); ++i) - os << '{' << cell(i) << '}'; - if (nargs() == 0) - os.pendingSpace(true); - if (lock_ && !os.latex()) { - os << "\\lyxlock"; - os.pendingSpace(true); - } -} - - -void InsetMathNest::normalize(NormalStream & os) const -{ - os << '[' << name().c_str(); - for (size_t i = 0; i < nargs(); ++i) - os << ' ' << cell(i); - os << ']'; -} - - -int InsetMathNest::latex(Buffer const &, odocstream & os, - OutputParams const & runparams) const -{ - WriteStream wi(os, runparams.moving_arg, true); - write(wi); - return wi.line(); -} - - -bool InsetMathNest::notifyCursorLeaves(LCursor & /*cur*/) -{ -#ifdef WITH_WARNINGS -#warning look here -#endif -#if 0 - MathArray & ar = cur.cell(); - // remove base-only "scripts" - for (pos_type i = 0; i + 1 < ar.size(); ++i) { - InsetMathScript * p = operator[](i).nucleus()->asScriptInset(); - if (p && p->nargs() == 1) { - MathArray ar = p->nuc(); - erase(i); - insert(i, ar); - cur.adjust(i, ar.size() - 1); - } - } - - // glue adjacent font insets of the same kind - for (pos_type i = 0; i + 1 < size(); ++i) { - InsetMathFont * p = operator[](i).nucleus()->asFontInset(); - InsetMathFont const * q = operator[](i + 1)->asFontInset(); - if (p && q && p->name() == q->name()) { - p->cell(0).append(q->cell(0)); - erase(i + 1); - cur.adjust(i, -1); - } - } -#endif - return false; -} - - -void InsetMathNest::handleFont - (LCursor & cur, docstring const & arg, char const * const font) -{ - handleFont(cur, arg, from_ascii(font)); -} - - -void InsetMathNest::handleFont - (LCursor & cur, docstring const & arg, docstring const & font) -{ - // this whole function is a hack and won't work for incremental font - // changes... - - if (cur.inset().asInsetMath()->name() == font) { - recordUndoInset(cur, Undo::ATOMIC); - cur.handleFont(to_utf8(font)); - } else { - recordUndo(cur, Undo::ATOMIC); - cur.handleNest(createInsetMath(font)); - cur.insert(arg); - } -} - - -void InsetMathNest::handleFont2(LCursor & cur, docstring const & arg) -{ - recordUndo(cur, Undo::ATOMIC); - LyXFont font; - bool b; - bv_funcs::string2font(to_utf8(arg), font, b); - if (font.color() != LColor::inherit) { - MathAtom at = MathAtom(new InsetMathColor(true, font.color())); - cur.handleNest(at, 0); - } -} - - -void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd) -{ - //lyxerr << "InsetMathNest: request: " << cmd << std::endl; - //CursorSlice sl = cur.current(); - - switch (cmd.action) { - - case LFUN_PASTE: { - recordUndo(cur); - cur.message(_("Paste")); - replaceSelection(cur); - docstring topaste; - if (cmd.argument().empty() && !theClipboard().isInternal()) - topaste = theClipboard().getAsText(); - else { - size_t n = 0; - idocstringstream is(cmd.argument()); - is >> n; - topaste = cap::getSelection(cur.buffer(), n); - } - cur.niceInsert(topaste); - cur.clearSelection(); // bug 393 - cur.bv().switchKeyMap(); - finishUndo(); - break; - } - - case LFUN_CUT: - recordUndo(cur); - cutSelection(cur, true, true); - cur.message(_("Cut")); - // Prevent stale position >= size crash - // Probably not necessary anymore, see eraseSelection (gb 2005-10-09) - cur.normalize(); - break; - - case LFUN_COPY: - copySelection(cur); - cur.message(_("Copy")); - break; - - case LFUN_MOUSE_PRESS: - lfunMousePress(cur, cmd); - break; - - case LFUN_MOUSE_MOTION: - lfunMouseMotion(cur, cmd); - break; - - case LFUN_MOUSE_RELEASE: - lfunMouseRelease(cur, cmd); - break; - - case LFUN_FINISHED_LEFT: - cur.bv().cursor() = cur; - break; - - case LFUN_FINISHED_RIGHT: - ++cur.pos(); - cur.bv().cursor() = cur; - break; - - case LFUN_FINISHED_UP: - cur.bv().cursor() = cur; - break; - - case LFUN_FINISHED_DOWN: - ++cur.pos(); - cur.bv().cursor() = cur; - break; - - case LFUN_CHAR_FORWARD: - cur.updateFlags(Update::Decoration | Update::FitCursor); - case LFUN_CHAR_FORWARD_SELECT: - cur.selHandle(cmd.action == LFUN_CHAR_FORWARD_SELECT); - cur.autocorrect() = false; - cur.clearTargetX(); - cur.macroModeClose(); - if (cur.pos() != cur.lastpos() && cur.openable(cur.nextAtom())) { - cur.pushLeft(*cur.nextAtom().nucleus()); - cur.inset().idxFirst(cur); - } else if (cur.posRight() || idxRight(cur) - || cur.popRight() || cur.selection()) - ; - else { - cmd = FuncRequest(LFUN_FINISHED_RIGHT); - cur.undispatched(); - } - break; - - case LFUN_CHAR_BACKWARD: - cur.updateFlags(Update::Decoration | Update::FitCursor); - case LFUN_CHAR_BACKWARD_SELECT: - cur.selHandle(cmd.action == LFUN_CHAR_BACKWARD_SELECT); - cur.autocorrect() = false; - cur.clearTargetX(); - cur.macroModeClose(); - if (cur.pos() != 0 && cur.openable(cur.prevAtom())) { - cur.posLeft(); - cur.push(*cur.nextAtom().nucleus()); - cur.inset().idxLast(cur); - } else if (cur.posLeft() || idxLeft(cur) - || cur.popLeft() || cur.selection()) - ; - else { - cmd = FuncRequest(LFUN_FINISHED_LEFT); - cur.undispatched(); - } - break; - - case LFUN_UP: - cur.updateFlags(Update::Decoration | Update::FitCursor); - case LFUN_UP_SELECT: - // FIXME Tried to use clearTargetX and macroModeClose, crashed on cur.up() - if (cur.inMacroMode()) { - // Make Helge happy - cur.macroModeClose(); - break; - } - cur.selHandle(cmd.action == LFUN_UP_SELECT); - if (!cur.up()) { - cmd = FuncRequest(LFUN_FINISHED_UP); - cur.undispatched(); - } - // fixes bug 1598. Please check! - cur.normalize(); - break; - - case LFUN_DOWN: - cur.updateFlags(Update::Decoration | Update::FitCursor); - case LFUN_DOWN_SELECT: - if (cur.inMacroMode()) { - cur.macroModeClose(); - break; - } - cur.selHandle(cmd.action == LFUN_DOWN_SELECT); - if (!cur.down()) { - cmd = FuncRequest(LFUN_FINISHED_DOWN); - cur.undispatched(); - } - // fixes bug 1598. Please check! - cur.normalize(); - break; - - case LFUN_MOUSE_DOUBLE: - case LFUN_MOUSE_TRIPLE: - case LFUN_WORD_SELECT: - cur.pos() = 0; - cur.idx() = 0; - cur.resetAnchor(); - cur.selection() = true; - cur.pos() = cur.lastpos(); - cur.idx() = cur.lastidx(); - cap::saveSelection(cur); - break; - - case LFUN_PARAGRAPH_UP: - case LFUN_PARAGRAPH_DOWN: - cur.updateFlags(Update::Decoration | Update::FitCursor); - case LFUN_PARAGRAPH_UP_SELECT: - case LFUN_PARAGRAPH_DOWN_SELECT: - break; - - case LFUN_LINE_BEGIN: - case LFUN_WORD_BACKWARD: - cur.updateFlags(Update::Decoration | Update::FitCursor); - case LFUN_LINE_BEGIN_SELECT: - case LFUN_WORD_BACKWARD_SELECT: - cur.selHandle(cmd.action == LFUN_WORD_BACKWARD_SELECT || - cmd.action == LFUN_LINE_BEGIN_SELECT); - cur.macroModeClose(); - if (cur.pos() != 0) { - cur.pos() = 0; - } else if (cur.col() != 0) { - cur.idx() -= cur.col(); - cur.pos() = 0; - } else if (cur.idx() != 0) { - cur.idx() = 0; - cur.pos() = 0; - } else { - cmd = FuncRequest(LFUN_FINISHED_LEFT); - cur.undispatched(); - } - break; - - case LFUN_WORD_FORWARD: - case LFUN_LINE_END: - cur.updateFlags(Update::Decoration | Update::FitCursor); - case LFUN_WORD_FORWARD_SELECT: - case LFUN_LINE_END_SELECT: - cur.selHandle(cmd.action == LFUN_WORD_FORWARD_SELECT || - cmd.action == LFUN_LINE_END_SELECT); - cur.macroModeClose(); - cur.clearTargetX(); - if (cur.pos() != cur.lastpos()) { - cur.pos() = cur.lastpos(); - } else if (ncols() && (cur.col() != cur.lastcol())) { - cur.idx() = cur.idx() - cur.col() + cur.lastcol(); - cur.pos() = cur.lastpos(); - } else if (cur.idx() != cur.lastidx()) { - cur.idx() = cur.lastidx(); - cur.pos() = cur.lastpos(); - } else { - cmd = FuncRequest(LFUN_FINISHED_RIGHT); - cur.undispatched(); - } - break; - - case LFUN_SCREEN_UP_SELECT: - case LFUN_SCREEN_UP: - cmd = FuncRequest(LFUN_FINISHED_LEFT); - cur.undispatched(); - break; - - case LFUN_SCREEN_DOWN_SELECT: - case LFUN_SCREEN_DOWN: - cmd = FuncRequest(LFUN_FINISHED_RIGHT); - cur.undispatched(); - break; - - case LFUN_CELL_FORWARD: - cur.updateFlags(Update::Decoration | Update::FitCursor); - cur.inset().idxNext(cur); - break; - - case LFUN_CELL_BACKWARD: - cur.updateFlags(Update::Decoration | Update::FitCursor); - cur.inset().idxPrev(cur); - break; - - case LFUN_WORD_DELETE_BACKWARD: - case LFUN_CHAR_DELETE_BACKWARD: - if (cur.pos() == 0) - // May affect external cell: - recordUndoInset(cur, Undo::ATOMIC); - else - recordUndo(cur, Undo::ATOMIC); - // if the inset can not be removed from within, delete it - if (!cur.backspace()) { - FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD); - cur.innerText()->dispatch(cur, cmd); - } - break; - - case LFUN_WORD_DELETE_FORWARD: - case LFUN_CHAR_DELETE_FORWARD: - if (cur.pos() == cur.lastpos()) - // May affect external cell: - recordUndoInset(cur, Undo::ATOMIC); - else - recordUndo(cur, Undo::ATOMIC); - // if the inset can not be removed from within, delete it - if (!cur.erase()) { - FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD); - cur.innerText()->dispatch(cur, cmd); - } - break; - - case LFUN_ESCAPE: - if (cur.selection()) - cur.clearSelection(); - else { - cmd = FuncRequest(LFUN_FINISHED_RIGHT); - cur.undispatched(); - } - break; - - case LFUN_INSET_TOGGLE: - recordUndo(cur); - lock(!lock()); - cur.popRight(); - break; - - case LFUN_SELF_INSERT: - if (cmd.argument().size() != 1) { - recordUndo(cur); - docstring const arg = cmd.argument(); - if (!interpretString(cur, arg)) - cur.insert(arg); - break; - } - // Don't record undo steps if we are in macro mode and - // cmd.argument is the next character of the macro name. - // Otherwise we'll get an invalid cursor if we undo after - // the macro was finished and the macro is a known command, - // e.g. sqrt. LCursor::macroModeClose replaces in this case - // the InsetMathUnknown with name "frac" by an empty - // InsetMathFrac -> a pos value > 0 is invalid. - // A side effect is that an undo before the macro is finished - // undoes the complete macro, not only the last character. - if (!cur.inMacroMode()) - recordUndo(cur); - - // spacial handling of space. If we insert an inset - // via macro mode, we want to put the cursor inside it - // if relevant. Think typing "\frac". - if (cmd.argument()[0] == ' ' - && cur.inMacroMode() && cur.macroName() != "\\" - && cur.macroModeClose()) { - MathAtom const atom = cur.prevAtom(); - if (atom->asNestInset() && atom->nargs() > 0) { - cur.posLeft(); - cur.pushLeft(*cur.nextInset()); - } - } else if (!interpretChar(cur, cmd.argument()[0])) { - cmd = FuncRequest(LFUN_FINISHED_RIGHT); - cur.undispatched(); - } - break; - - //case LFUN_SERVER_GET_XY: - // sprintf(dispatch_buffer, "%d %d",); - // break; - - case LFUN_SERVER_SET_XY: { - lyxerr << "LFUN_SERVER_SET_XY broken!" << endl; - int x = 0; - int y = 0; - istringstream is(to_utf8(cmd.argument())); - is >> x >> y; - cur.setScreenPos(x, y); - break; - } - - // Special casing for superscript in case of LyX handling - // dead-keys: - case LFUN_ACCENT_CIRCUMFLEX: - if (cmd.argument().empty()) { - // do superscript if LyX handles - // deadkeys - recordUndo(cur, Undo::ATOMIC); - script(cur, true, grabAndEraseSelection(cur)); - } - break; - - case LFUN_ACCENT_UMLAUT: - case LFUN_ACCENT_ACUTE: - case LFUN_ACCENT_GRAVE: - case LFUN_ACCENT_BREVE: - case LFUN_ACCENT_DOT: - case LFUN_ACCENT_MACRON: - case LFUN_ACCENT_CARON: - case LFUN_ACCENT_TILDE: - case LFUN_ACCENT_CEDILLA: - case LFUN_ACCENT_CIRCLE: - case LFUN_ACCENT_UNDERDOT: - case LFUN_ACCENT_TIE: - case LFUN_ACCENT_OGONEK: - case LFUN_ACCENT_HUNGARIAN_UMLAUT: - break; - - // Math fonts - case LFUN_FONT_FREE_APPLY: - case LFUN_FONT_FREE_UPDATE: - handleFont2(cur, cmd.argument()); - break; - - case LFUN_FONT_BOLD: - if (currentMode() == TEXT_MODE) - handleFont(cur, cmd.argument(), "textbf"); - else - handleFont(cur, cmd.argument(), "mathbf"); - break; - case LFUN_FONT_SANS: - if (currentMode() == TEXT_MODE) - handleFont(cur, cmd.argument(), "textsf"); - else - handleFont(cur, cmd.argument(), "mathsf"); - break; - case LFUN_FONT_EMPH: - if (currentMode() == TEXT_MODE) - handleFont(cur, cmd.argument(), "emph"); - else - handleFont(cur, cmd.argument(), "mathcal"); - break; - case LFUN_FONT_ROMAN: - if (currentMode() == TEXT_MODE) - handleFont(cur, cmd.argument(), "textrm"); - else - handleFont(cur, cmd.argument(), "mathrm"); - break; - case LFUN_FONT_CODE: - if (currentMode() == TEXT_MODE) - handleFont(cur, cmd.argument(), "texttt"); - else - handleFont(cur, cmd.argument(), "mathtt"); - break; - case LFUN_FONT_FRAK: - handleFont(cur, cmd.argument(), "mathfrak"); - break; - case LFUN_FONT_ITAL: - if (currentMode() == TEXT_MODE) - handleFont(cur, cmd.argument(), "textit"); - else - handleFont(cur, cmd.argument(), "mathit"); - break; - case LFUN_FONT_NOUN: - if (currentMode() == TEXT_MODE) - // FIXME: should be "noun" - handleFont(cur, cmd.argument(), "textsc"); - else - handleFont(cur, cmd.argument(), "mathbb"); - break; - /* - case LFUN_FONT_FREE_APPLY: - handleFont(cur, cmd.argument(), "textrm"); - break; - */ - case LFUN_FONT_DEFAULT: - handleFont(cur, cmd.argument(), "textnormal"); - break; - - case LFUN_MATH_MODE: { -#if 1 - // ignore math-mode on when already in math mode - if (currentMode() == InsetBase::MATH_MODE && cmd.argument() == "on") - break; - cur.macroModeClose(); - docstring const save_selection = grabAndEraseSelection(cur); - selClearOrDel(cur); - //cur.plainInsert(MathAtom(new InsetMathMBox(cur.bv()))); - cur.plainInsert(MathAtom(new InsetMathBox(from_ascii("mbox")))); - cur.posLeft(); - cur.pushLeft(*cur.nextInset()); - cur.niceInsert(save_selection); -#else - if (currentMode() == InsetBase::TEXT_MODE) { - cur.niceInsert(MathAtom(new InsetMathHull("simple"))); - cur.message(_("create new math text environment ($...$)")); - } else { - handleFont(cur, cmd.argument(), "textrm"); - cur.message(_("entered math text mode (textrm)")); - } -#endif - break; - } - - case LFUN_MATH_SIZE: -#if 0 - recordUndo(cur); - cur.setSize(arg); -#endif - break; - - case LFUN_MATH_MATRIX: { - recordUndo(cur, Undo::ATOMIC); - unsigned int m = 1; - unsigned int n = 1; - docstring v_align; - docstring h_align; - idocstringstream is(cmd.argument()); - is >> m >> n >> v_align >> h_align; - if (m < 1) - m = 1; - if (n < 1) - n = 1; - v_align += 'c'; - cur.niceInsert( - MathAtom(new InsetMathArray(from_ascii("array"), m, n, (char)v_align[0], h_align))); - break; - } - - case LFUN_MATH_DELIM: { - docstring ls; - docstring rs = support::split(cmd.argument(), ls, ' '); - // Reasonable default values - if (ls.empty()) - ls = '('; - if (rs.empty()) - rs = ')'; - recordUndo(cur, Undo::ATOMIC); - cur.handleNest(MathAtom(new InsetMathDelim(ls, rs))); - break; - } - - case LFUN_MATH_BIGDELIM: { - docstring const lname = from_utf8(cmd.getArg(0)); - docstring const ldelim = from_utf8(cmd.getArg(1)); - docstring const rname = from_utf8(cmd.getArg(2)); - docstring const rdelim = from_utf8(cmd.getArg(3)); - latexkeys const * l = in_word_set(lname); - bool const have_l = l && l->inset == "big" && - InsetMathBig::isBigInsetDelim(ldelim); - l = in_word_set(rname); - bool const have_r = l && l->inset == "big" && - InsetMathBig::isBigInsetDelim(rdelim); - // We mimic LFUN_MATH_DELIM in case we have an empty left - // or right delimiter. - if (have_l || have_r) { - recordUndo(cur, Undo::ATOMIC); - docstring const selection = grabAndEraseSelection(cur); - selClearOrDel(cur); - if (have_l) - cur.insert(MathAtom(new InsetMathBig(lname, - ldelim))); - cur.niceInsert(selection); - if (have_r) - cur.insert(MathAtom(new InsetMathBig(rname, - rdelim))); - } - // Don't call cur.undispatched() if we did nothing, this would - // lead to infinite recursion via LyXText::dispatch(). - break; - } - - case LFUN_SPACE_INSERT: - case LFUN_MATH_SPACE: - recordUndo(cur, Undo::ATOMIC); - cur.insert(MathAtom(new InsetMathSpace(from_ascii(",")))); - break; - - case LFUN_ERT_INSERT: - // interpret this as if a backslash was typed - recordUndo(cur, Undo::ATOMIC); - interpretChar(cur, '\\'); - break; - - case LFUN_MATH_SUBSCRIPT: - // interpret this as if a _ was typed - recordUndo(cur, Undo::ATOMIC); - interpretChar(cur, '_'); - break; - - case LFUN_MATH_SUPERSCRIPT: - // interpret this as if a ^ was typed - recordUndo(cur, Undo::ATOMIC); - interpretChar(cur, '^'); - break; - - case LFUN_QUOTE_INSERT: - // interpret this as if a straight " was typed - recordUndo(cur, Undo::ATOMIC); - interpretChar(cur, '\"'); - break; - -// FIXME: We probably should swap parts of "math-insert" and "self-insert" -// handling such that "self-insert" works on "arbitrary stuff" too, and -// math-insert only handles special math things like "matrix". - case LFUN_MATH_INSERT: { - recordUndo(cur, Undo::ATOMIC); - if (cmd.argument() == "^" || cmd.argument() == "_") { - interpretChar(cur, cmd.argument()[0]); - } else - cur.niceInsert(cmd.argument()); - break; - } - - case LFUN_DIALOG_SHOW_NEW_INSET: { - docstring const & name = cmd.argument(); - string data; - if (name == "ref") { - RefInset tmp(name); - data = tmp.createDialogStr(to_utf8(name)); - } - cur.bv().showInsetDialog(to_utf8(name), data, 0); - break; - } - - case LFUN_INSET_INSERT: { - MathArray ar; - if (createInsetMath_fromDialogStr(cmd.argument(), ar)) { - recordUndo(cur); - cur.insert(ar); - } else - cur.undispatched(); - break; - } - - default: - InsetMathDim::doDispatch(cur, cmd); - break; - } -} - - -bool InsetMathNest::getStatus(LCursor & cur, FuncRequest const & cmd, - FuncStatus & flag) const -{ - // the font related toggles - //string tc = "mathnormal"; - bool ret = true; - string const arg = to_utf8(cmd.argument()); - switch (cmd.action) { - case LFUN_TABULAR_FEATURE: - flag.enabled(false); - break; -#if 0 - case LFUN_TABULAR_FEATURE: - // FIXME: check temporarily disabled - // valign code - char align = mathcursor::valign(); - if (align == '\0') { - enable = false; - break; - } - if (cmd.argument().empty()) { - flag.clear(); - break; - } - if (!contains("tcb", cmd.argument()[0])) { - enable = false; - break; - } - flag.setOnOff(cmd.argument()[0] == align); - break; -#endif - /// We have to handle them since 1.4 blocks all unhandled actions - case LFUN_FONT_ITAL: - case LFUN_FONT_BOLD: - case LFUN_FONT_SANS: - case LFUN_FONT_EMPH: - case LFUN_FONT_CODE: - case LFUN_FONT_NOUN: - case LFUN_FONT_ROMAN: - case LFUN_FONT_DEFAULT: - flag.enabled(true); - break; - case LFUN_MATH_MUTATE: - //flag.setOnOff(mathcursor::formula()->hullType() == to_utf8(cmd.argument())); - flag.setOnOff(false); - break; - - // we just need to be in math mode to enable that - case LFUN_MATH_SIZE: - case LFUN_MATH_SPACE: - case LFUN_MATH_LIMITS: - case LFUN_MATH_NONUMBER: - case LFUN_MATH_NUMBER: - case LFUN_MATH_EXTERN: - flag.enabled(true); - break; - - case LFUN_FONT_FRAK: - flag.enabled(currentMode() != TEXT_MODE); - break; - - case LFUN_MATH_INSERT: { - bool const textarg = - arg == "\\textbf" || arg == "\\textsf" || - arg == "\\textrm" || arg == "\\textmd" || - arg == "\\textit" || arg == "\\textsc" || - arg == "\\textsl" || arg == "\\textup" || - arg == "\\texttt" || arg == "\\textbb" || - arg == "\\textnormal"; - flag.enabled(currentMode() != TEXT_MODE || textarg); - break; - } - - case LFUN_MATH_MATRIX: - flag.enabled(currentMode() == MATH_MODE); - break; - - case LFUN_INSET_INSERT: { - // Don't test createMathInset_fromDialogStr(), since - // getStatus is not called with a valid reference and the - // dialog would not be applyable. - string const name = cmd.getArg(0); - flag.enabled(name == "ref"); - break; - } - - case LFUN_MATH_DELIM: - case LFUN_MATH_BIGDELIM: - // Don't do this with multi-cell selections - flag.enabled(cur.selBegin().idx() == cur.selEnd().idx()); - break; - - default: - ret = false; - break; - } - return ret; -} - - -void InsetMathNest::edit(LCursor & cur, bool left) -{ - cur.push(*this); - cur.idx() = left ? 0 : cur.lastidx(); - cur.pos() = left ? 0 : cur.lastpos(); - cur.resetAnchor(); - //lyxerr << "InsetMathNest::edit, cur:\n" << cur << endl; -} - - -InsetBase * InsetMathNest::editXY(LCursor & cur, int x, int y) -{ - int idx_min = 0; - int dist_min = 1000000; - for (idx_type i = 0, n = nargs(); i != n; ++i) { - int const d = cell(i).dist(cur.bv(), x, y); - if (d < dist_min) { - dist_min = d; - idx_min = i; - } - } - MathArray & ar = cell(idx_min); - cur.push(*this); - cur.idx() = idx_min; - cur.pos() = ar.x2pos(x - ar.xo(cur.bv())); - - //lyxerr << "found cell : " << idx_min << " pos: " << cur.pos() << endl; - if (dist_min == 0) { - // hit inside cell - for (pos_type i = 0, n = ar.size(); i < n; ++i) - if (ar[i]->covers(cur.bv(), x, y)) - return ar[i].nucleus()->editXY(cur, x, y); - } - return this; -} - - -void InsetMathNest::lfunMousePress(LCursor & cur, FuncRequest & cmd) -{ - //lyxerr << "## lfunMousePress: buttons: " << cmd.button() << endl; - BufferView & bv = cur.bv(); - if (cmd.button() == mouse_button::button1) { - //lyxerr << "## lfunMousePress: setting cursor to: " << cur << endl; - bv.mouseSetCursor(cur); - // Update the cursor update flags as needed: - // - // Update::Decoration: tells to update the decoration (visual box - // corners that define the inset)/ - // Update::FitCursor: adjust the screen to the cursor position if - // needed - // cur.result().update(): don't overwrite previously set flags. - cur.updateFlags(Update::Decoration | Update::FitCursor | cur.result().update()); - } else if (cmd.button() == mouse_button::button2) { - MathArray ar; - if (cap::selection()) { - // See comment in LyXText::dispatch why we do this - cap::copySelectionToStack(); - cmd = FuncRequest(LFUN_PASTE, "0"); - doDispatch(cur, cmd); - } else - asArray(theSelection().get(), ar); - - cur.insert(ar); - bv.mouseSetCursor(cur); - } -} - - -void InsetMathNest::lfunMouseMotion(LCursor & cur, FuncRequest & cmd) -{ - // only select with button 1 - if (cmd.button() == mouse_button::button1) { - LCursor & bvcur = cur.bv().cursor(); - if (bvcur.anchor_.hasPart(cur)) { - //lyxerr << "## lfunMouseMotion: cursor: " << cur << endl; - bvcur.setCursor(cur); - bvcur.selection() = true; - //lyxerr << "MOTION " << bvcur << endl; - } else - cur.undispatched(); - } -} - - -void InsetMathNest::lfunMouseRelease(LCursor & cur, FuncRequest & cmd) -{ - //lyxerr << "## lfunMouseRelease: buttons: " << cmd.button() << endl; - - if (cmd.button() == mouse_button::button1) { - if (!cur.selection()) - cur.noUpdate(); - else { - LCursor & bvcur = cur.bv().cursor(); - bvcur.selection() = true; - cap::saveSelection(bvcur); - } - return; - } - - cur.undispatched(); -} - - -bool InsetMathNest::interpretChar(LCursor & cur, char_type c) -{ - //lyxerr << "interpret 2: '" << c << "'" << endl; - docstring save_selection; - if (c == '^' || c == '_') - save_selection = grabAndEraseSelection(cur); - - cur.clearTargetX(); - - // handle macroMode - if (cur.inMacroMode()) { - docstring name = cur.macroName(); - - /// are we currently typing '#1' or '#2' or...? - if (name == "\\#") { - cur.backspace(); - int n = c - '0'; - if (n >= 1 && n <= 9) - cur.insert(new MathMacroArgument(n)); - return true; - } - - if (isAlphaASCII(c)) { - cur.activeMacro()->setName(name + docstring(1, c)); - return true; - } - - // handle 'special char' macros - if (name == "\\") { - // remove the '\\' - if (c == '\\') { - cur.backspace(); - if (currentMode() == InsetMath::TEXT_MODE) - cur.niceInsert(createInsetMath("textbackslash")); - else - cur.niceInsert(createInsetMath("backslash")); - } else if (c == '{') { - cur.backspace(); - cur.niceInsert(MathAtom(new InsetMathBrace)); - } else if (c == '%') { - cur.backspace(); - cur.niceInsert(MathAtom(new InsetMathComment)); - } else if (c == '#') { - BOOST_ASSERT(cur.activeMacro()); - cur.activeMacro()->setName(name + docstring(1, c)); - } else { - cur.backspace(); - cur.niceInsert(createInsetMath(docstring(1, c))); - } - return true; - } - - // One character big delimiters. The others are handled in - // interpretString(). - latexkeys const * l = in_word_set(name.substr(1)); - if (name[0] == '\\' && l && l->inset == "big") { - docstring delim; - switch (c) { - case '{': - delim = from_ascii("\\{"); - break; - case '}': - delim = from_ascii("\\}"); - break; - default: - delim = docstring(1, c); - break; - } - if (InsetMathBig::isBigInsetDelim(delim)) { - // name + delim ared a valid InsetMathBig. - // We can't use cur.macroModeClose() because - // it does not handle delim. - InsetMathUnknown * p = cur.activeMacro(); - p->finalize(); - --cur.pos(); - cur.cell().erase(cur.pos()); - cur.plainInsert(MathAtom( - new InsetMathBig(name.substr(1), delim))); - return true; - } - } - - // leave macro mode and try again if necessary - cur.macroModeClose(); - if (c == '{') - cur.niceInsert(MathAtom(new InsetMathBrace)); - else if (c != ' ') - interpretChar(cur, c); - return true; - } - - // This is annoying as one has to press far too often. - // Disable it. - -#if 0 - // leave autocorrect mode if necessary - if (autocorrect() && c == ' ') { - autocorrect() = false; - return true; - } -#endif - - // just clear selection on pressing the space bar - if (cur.selection() && c == ' ') { - cur.selection() = false; - return true; - } - - selClearOrDel(cur); - - if (c == '\\') { - //lyxerr << "starting with macro" << endl; - cur.insert(MathAtom(new InsetMathUnknown(from_ascii("\\"), false))); - return true; - } - - if (c == '\n') { - if (currentMode() == InsetMath::TEXT_MODE) - cur.insert(c); - return true; - } - - if (c == ' ') { - if (currentMode() == InsetMath::TEXT_MODE) { - // insert spaces in text mode, - // but suppress direct insertion of two spaces in a row - // the still allows typing 'a' and deleting the 'a', but - // it is better than nothing... - if (!cur.pos() != 0 || cur.prevAtom()->getChar() != ' ') { - cur.insert(c); - // FIXME: we have to enable full redraw here because of the - // visual box corners that define the inset. If we know for - // sure that we stay within the same cell we can optimize for - // that using: - //cur.updateFlags(Update::SinglePar | Update::FitCursor); - } - return true; - } - if (cur.pos() != 0 && cur.prevAtom()->asSpaceInset()) { - cur.prevAtom().nucleus()->asSpaceInset()->incSpace(); - // FIXME: we have to enable full redraw here because of the - // visual box corners that define the inset. If we know for - // sure that we stay within the same cell we can optimize for - // that using: - //cur.updateFlags(Update::SinglePar | Update::FitCursor); - return true; - } - - if (cur.popRight()) { - // FIXME: we have to enable full redraw here because of the - // visual box corners that define the inset. If we know for - // sure that we stay within the same cell we can optimize for - // that using: - //cur.updateFlags(Update::FitCursor); - return true; - } - - // if we are at the very end, leave the formula - return cur.pos() != cur.lastpos(); - } - - // These shouldn't work in text mode: - if (currentMode() != InsetMath::TEXT_MODE) { - if (c == '_') { - script(cur, false, save_selection); - return true; - } - if (c == '^') { - script(cur, true, save_selection); - return true; - } - if (c == '~') { - cur.niceInsert(createInsetMath("sim")); - return true; - } - } - - if (c == '{' || c == '}' || c == '&' || c == '$' || c == '#' || - c == '%' || c == '_' || c == '^') { - cur.niceInsert(createInsetMath(docstring(1, c))); - return true; - } - - - // try auto-correction - //if (autocorrect() && hasPrevAtom() && math_autocorrect(prevAtom(), c)) - // return true; - - // no special circumstances, so insert the character without any fuss - cur.insert(c); - cur.autocorrect() = true; - return true; -} - - -bool InsetMathNest::interpretString(LCursor & cur, docstring const & str) -{ - // Create a InsetMathBig from cur.cell()[cur.pos() - 1] and t if - // possible - if (!cur.empty() && cur.pos() > 0 && - cur.cell()[cur.pos() - 1]->asUnknownInset()) { - if (InsetMathBig::isBigInsetDelim(str)) { - docstring prev = asString(cur.cell()[cur.pos() - 1]); - if (prev[0] == '\\') { - prev = prev.substr(1); - latexkeys const * l = in_word_set(prev); - if (l && l->inset == "big") { - cur.cell()[cur.pos() - 1] = - MathAtom(new InsetMathBig(prev, str)); - return true; - } - } - } - } - return false; -} - - -bool InsetMathNest::script(LCursor & cur, bool up, - docstring const & save_selection) -{ - // Hack to get \^ and \_ working - //lyxerr << "handling script: up: " << up << endl; - if (cur.inMacroMode() && cur.macroName() == "\\") { - if (up) - cur.niceInsert(createInsetMath("mathcircumflex")); - else - interpretChar(cur, '_'); - return true; - } - - cur.macroModeClose(); - if (asScriptInset() && cur.idx() == 0) { - // we are in a nucleus of a script inset, move to _our_ script - InsetMathScript * inset = asScriptInset(); - //lyxerr << " going to cell " << inset->idxOfScript(up) << endl; - inset->ensure(up); - cur.idx() = inset->idxOfScript(up); - cur.pos() = 0; - } else if (cur.pos() != 0 && cur.prevAtom()->asScriptInset()) { - --cur.pos(); - InsetMathScript * inset = cur.nextAtom().nucleus()->asScriptInset(); - cur.push(*inset); - inset->ensure(up); - cur.idx() = inset->idxOfScript(up); - cur.pos() = cur.lastpos(); - } else { - // convert the thing to our left to a scriptinset or create a new - // one if in the very first position of the array - if (cur.pos() == 0) { - //lyxerr << "new scriptinset" << endl; - cur.insert(new InsetMathScript(up)); - } else { - //lyxerr << "converting prev atom " << endl; - cur.prevAtom() = MathAtom(new InsetMathScript(cur.prevAtom(), up)); - } - --cur.pos(); - InsetMathScript * inset = cur.nextAtom().nucleus()->asScriptInset(); - // See comment in MathParser.cpp for special handling of {}-bases - - cur.push(*inset); - cur.idx() = 1; - cur.pos() = 0; - } - //lyxerr << "inserting selection 1:\n" << save_selection << endl; - cur.niceInsert(save_selection); - cur.resetAnchor(); - //lyxerr << "inserting selection 2:\n" << save_selection << endl; - return true; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathNest.cpp b/src/mathed/InsetMathNest.cpp new file mode 100644 index 0000000000..1d18ae086e --- /dev/null +++ b/src/mathed/InsetMathNest.cpp @@ -0,0 +1,1469 @@ +/** + * \file InsetMathNest.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathNest.h" + +#include "InsetMathArray.h" +#include "InsetMathBig.h" +#include "InsetMathBox.h" +#include "InsetMathBrace.h" +#include "InsetMathColor.h" +#include "InsetMathComment.h" +#include "MathData.h" +#include "InsetMathDelim.h" +#include "MathFactory.h" +#include "InsetMathHull.h" +#include "MathStream.h" +#include "MathMacroArgument.h" +//#include "InsetMathMBox.h" +#include "MathParser.h" +#include "InsetMathScript.h" +#include "InsetMathSpace.h" +#include "InsetMathSymbol.h" +#include "MathSupport.h" +#include "InsetMathUnknown.h" +#include "InsetMathRef.h" + +#include "BufferView.h" +#include "CutAndPaste.h" +#include "FuncStatus.h" +#include "LColor.h" +#include "bufferview_funcs.h" +#include "coordcache.h" +#include "cursor.h" +#include "debug.h" +#include "dispatchresult.h" +#include "funcrequest.h" +#include "gettext.h" +#include "lyxtext.h" +#include "outputparams.h" +#include "undo.h" + +#include "support/lstrings.h" +#include "support/textutils.h" + +#include "frontends/Clipboard.h" +#include "frontends/Painter.h" +#include "frontends/Selection.h" + +#include "funcrequest.h" +#include "lyxserver.h" +#include "lyxsocket.h" + +#include + + +namespace lyx { + +using cap::copySelection; +using cap::grabAndEraseSelection; +using cap::cutSelection; +using cap::replaceSelection; +using cap::selClearOrDel; + +using std::endl; +using std::string; +using std::istringstream; + + +InsetMathNest::InsetMathNest(idx_type nargs) + : cells_(nargs), lock_(false) +{} + + +InsetMath::idx_type InsetMathNest::nargs() const +{ + return cells_.size(); +} + + +void InsetMathNest::cursorPos(BufferView const & bv, + CursorSlice const & sl, bool /*boundary*/, + int & x, int & y) const +{ +// FIXME: This is a hack. Ideally, the coord cache should not store +// absolute positions, but relative ones. This would mean to call +// setXY() not in MathArray::draw(), but in the parent insets' draw() +// with the correctly adjusted x,y values. But this means that we'd have +// to touch all (math)inset's draw() methods. Right now, we'll store +// absolute value, and make them here relative, only to make them +// absolute again when actually drawing the cursor. What a mess. + BOOST_ASSERT(ptr_cmp(&sl.inset(), this)); + MathArray const & ar = sl.cell(); + CoordCache const & coord_cache = bv.coordCache(); + if (!coord_cache.getArrays().has(&ar)) { + // this can (semi-)legally happen if we just created this cell + // and it never has been drawn before. So don't ASSERT. + //lyxerr << "no cached data for array " << &ar << endl; + x = 0; + y = 0; + return; + } + Point const pt = coord_cache.getArrays().xy(&ar); + if (!coord_cache.getInsets().has(this)) { + // same as above + //lyxerr << "no cached data for inset " << this << endl; + x = 0; + y = 0; + return; + } + Point const pt2 = coord_cache.getInsets().xy(this); + //lyxerr << "retrieving position cache for MathArray " + // << pt.x_ << ' ' << pt.y_ << std::endl; + x = pt.x_ - pt2.x_ + ar.pos2x(sl.pos()); + y = pt.y_ - pt2.y_; +// lyxerr << "pt.y_ : " << pt.y_ << " pt2_.y_ : " << pt2.y_ +// << " asc: " << ascent() << " des: " << descent() +// << " ar.asc: " << ar.ascent() << " ar.des: " << ar.descent() << endl; + // move cursor visually into empty cells ("blue rectangles"); + if (ar.empty()) + x += 2; +} + + +void InsetMathNest::metrics(MetricsInfo const & mi) const +{ + MetricsInfo m = mi; + for (idx_type i = 0, n = nargs(); i != n; ++i) + cell(i).metrics(m); +} + + +bool InsetMathNest::idxNext(LCursor & cur) const +{ + BOOST_ASSERT(ptr_cmp(&cur.inset(), this)); + if (cur.idx() == cur.lastidx()) + return false; + ++cur.idx(); + cur.pos() = 0; + return true; +} + + +bool InsetMathNest::idxRight(LCursor & cur) const +{ + return idxNext(cur); +} + + +bool InsetMathNest::idxPrev(LCursor & cur) const +{ + BOOST_ASSERT(ptr_cmp(&cur.inset(), this)); + if (cur.idx() == 0) + return false; + --cur.idx(); + cur.pos() = cur.lastpos(); + return true; +} + + +bool InsetMathNest::idxLeft(LCursor & cur) const +{ + return idxPrev(cur); +} + + +bool InsetMathNest::idxFirst(LCursor & cur) const +{ + BOOST_ASSERT(ptr_cmp(&cur.inset(), this)); + if (nargs() == 0) + return false; + cur.idx() = 0; + cur.pos() = 0; + return true; +} + + +bool InsetMathNest::idxLast(LCursor & cur) const +{ + BOOST_ASSERT(ptr_cmp(&cur.inset(), this)); + if (nargs() == 0) + return false; + cur.idx() = cur.lastidx(); + cur.pos() = cur.lastpos(); + return true; +} + + +void InsetMathNest::dump() const +{ + odocstringstream oss; + WriteStream os(oss); + os << "---------------------------------------------\n"; + write(os); + os << "\n"; + for (idx_type i = 0, n = nargs(); i != n; ++i) + os << cell(i) << "\n"; + os << "---------------------------------------------\n"; + lyxerr << to_utf8(oss.str()); +} + + +void InsetMathNest::draw(PainterInfo & pi, int x, int y) const +{ +#if 0 + if (lock_) + pi.pain.fillRectangle(x, y - ascent(), width(), height(), + LColor::mathlockbg); +#endif + setPosCache(pi, x, y); +} + + +void InsetMathNest::drawSelection(PainterInfo & pi, int x, int y) const +{ + BufferView & bv = *pi.base.bv; + // this should use the x/y values given, not the cached values + LCursor & cur = bv.cursor(); + if (!cur.selection()) + return; + if (!ptr_cmp(&cur.inset(), this)) + return; + + // FIXME: hack to get position cache warm + pi.pain.setDrawingEnabled(false); + draw(pi, x, y); + pi.pain.setDrawingEnabled(true); + + CursorSlice s1 = cur.selBegin(); + CursorSlice s2 = cur.selEnd(); + + //lyxerr << "InsetMathNest::drawing selection: " + // << " s1: " << s1 << " s2: " << s2 << endl; + if (s1.idx() == s2.idx()) { + MathArray const & c = cell(s1.idx()); + int x1 = c.xo(bv) + c.pos2x(s1.pos()); + int y1 = c.yo(bv) - c.ascent(); + int x2 = c.xo(bv) + c.pos2x(s2.pos()); + int y2 = c.yo(bv) + c.descent(); + pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection); + //lyxerr << "InsetMathNest::drawing selection 3: " + // << " x1: " << x1 << " x2: " << x2 + // << " y1: " << y1 << " y2: " << y2 << endl; + } else { + for (idx_type i = 0; i < nargs(); ++i) { + if (idxBetween(i, s1.idx(), s2.idx())) { + MathArray const & c = cell(i); + int x1 = c.xo(bv); + int y1 = c.yo(bv) - c.ascent(); + int x2 = c.xo(bv) + c.width(); + int y2 = c.yo(bv) + c.descent(); + pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection); + } + } + } +} + + +void InsetMathNest::validate(LaTeXFeatures & features) const +{ + for (idx_type i = 0; i < nargs(); ++i) + cell(i).validate(features); +} + + +void InsetMathNest::replace(ReplaceData & rep) +{ + for (idx_type i = 0; i < nargs(); ++i) + cell(i).replace(rep); +} + + +bool InsetMathNest::contains(MathArray const & ar) const +{ + for (idx_type i = 0; i < nargs(); ++i) + if (cell(i).contains(ar)) + return true; + return false; +} + + +bool InsetMathNest::lock() const +{ + return lock_; +} + + +void InsetMathNest::lock(bool l) +{ + lock_ = l; +} + + +bool InsetMathNest::isActive() const +{ + return nargs() > 0; +} + + +MathArray InsetMathNest::glue() const +{ + MathArray ar; + for (size_t i = 0; i < nargs(); ++i) + ar.append(cell(i)); + return ar; +} + + +void InsetMathNest::write(WriteStream & os) const +{ + os << '\\' << name().c_str(); + for (size_t i = 0; i < nargs(); ++i) + os << '{' << cell(i) << '}'; + if (nargs() == 0) + os.pendingSpace(true); + if (lock_ && !os.latex()) { + os << "\\lyxlock"; + os.pendingSpace(true); + } +} + + +void InsetMathNest::normalize(NormalStream & os) const +{ + os << '[' << name().c_str(); + for (size_t i = 0; i < nargs(); ++i) + os << ' ' << cell(i); + os << ']'; +} + + +int InsetMathNest::latex(Buffer const &, odocstream & os, + OutputParams const & runparams) const +{ + WriteStream wi(os, runparams.moving_arg, true); + write(wi); + return wi.line(); +} + + +bool InsetMathNest::notifyCursorLeaves(LCursor & /*cur*/) +{ +#ifdef WITH_WARNINGS +#warning look here +#endif +#if 0 + MathArray & ar = cur.cell(); + // remove base-only "scripts" + for (pos_type i = 0; i + 1 < ar.size(); ++i) { + InsetMathScript * p = operator[](i).nucleus()->asScriptInset(); + if (p && p->nargs() == 1) { + MathArray ar = p->nuc(); + erase(i); + insert(i, ar); + cur.adjust(i, ar.size() - 1); + } + } + + // glue adjacent font insets of the same kind + for (pos_type i = 0; i + 1 < size(); ++i) { + InsetMathFont * p = operator[](i).nucleus()->asFontInset(); + InsetMathFont const * q = operator[](i + 1)->asFontInset(); + if (p && q && p->name() == q->name()) { + p->cell(0).append(q->cell(0)); + erase(i + 1); + cur.adjust(i, -1); + } + } +#endif + return false; +} + + +void InsetMathNest::handleFont + (LCursor & cur, docstring const & arg, char const * const font) +{ + handleFont(cur, arg, from_ascii(font)); +} + + +void InsetMathNest::handleFont + (LCursor & cur, docstring const & arg, docstring const & font) +{ + // this whole function is a hack and won't work for incremental font + // changes... + + if (cur.inset().asInsetMath()->name() == font) { + recordUndoInset(cur, Undo::ATOMIC); + cur.handleFont(to_utf8(font)); + } else { + recordUndo(cur, Undo::ATOMIC); + cur.handleNest(createInsetMath(font)); + cur.insert(arg); + } +} + + +void InsetMathNest::handleFont2(LCursor & cur, docstring const & arg) +{ + recordUndo(cur, Undo::ATOMIC); + LyXFont font; + bool b; + bv_funcs::string2font(to_utf8(arg), font, b); + if (font.color() != LColor::inherit) { + MathAtom at = MathAtom(new InsetMathColor(true, font.color())); + cur.handleNest(at, 0); + } +} + + +void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd) +{ + //lyxerr << "InsetMathNest: request: " << cmd << std::endl; + //CursorSlice sl = cur.current(); + + switch (cmd.action) { + + case LFUN_PASTE: { + recordUndo(cur); + cur.message(_("Paste")); + replaceSelection(cur); + docstring topaste; + if (cmd.argument().empty() && !theClipboard().isInternal()) + topaste = theClipboard().getAsText(); + else { + size_t n = 0; + idocstringstream is(cmd.argument()); + is >> n; + topaste = cap::getSelection(cur.buffer(), n); + } + cur.niceInsert(topaste); + cur.clearSelection(); // bug 393 + cur.bv().switchKeyMap(); + finishUndo(); + break; + } + + case LFUN_CUT: + recordUndo(cur); + cutSelection(cur, true, true); + cur.message(_("Cut")); + // Prevent stale position >= size crash + // Probably not necessary anymore, see eraseSelection (gb 2005-10-09) + cur.normalize(); + break; + + case LFUN_COPY: + copySelection(cur); + cur.message(_("Copy")); + break; + + case LFUN_MOUSE_PRESS: + lfunMousePress(cur, cmd); + break; + + case LFUN_MOUSE_MOTION: + lfunMouseMotion(cur, cmd); + break; + + case LFUN_MOUSE_RELEASE: + lfunMouseRelease(cur, cmd); + break; + + case LFUN_FINISHED_LEFT: + cur.bv().cursor() = cur; + break; + + case LFUN_FINISHED_RIGHT: + ++cur.pos(); + cur.bv().cursor() = cur; + break; + + case LFUN_FINISHED_UP: + cur.bv().cursor() = cur; + break; + + case LFUN_FINISHED_DOWN: + ++cur.pos(); + cur.bv().cursor() = cur; + break; + + case LFUN_CHAR_FORWARD: + cur.updateFlags(Update::Decoration | Update::FitCursor); + case LFUN_CHAR_FORWARD_SELECT: + cur.selHandle(cmd.action == LFUN_CHAR_FORWARD_SELECT); + cur.autocorrect() = false; + cur.clearTargetX(); + cur.macroModeClose(); + if (cur.pos() != cur.lastpos() && cur.openable(cur.nextAtom())) { + cur.pushLeft(*cur.nextAtom().nucleus()); + cur.inset().idxFirst(cur); + } else if (cur.posRight() || idxRight(cur) + || cur.popRight() || cur.selection()) + ; + else { + cmd = FuncRequest(LFUN_FINISHED_RIGHT); + cur.undispatched(); + } + break; + + case LFUN_CHAR_BACKWARD: + cur.updateFlags(Update::Decoration | Update::FitCursor); + case LFUN_CHAR_BACKWARD_SELECT: + cur.selHandle(cmd.action == LFUN_CHAR_BACKWARD_SELECT); + cur.autocorrect() = false; + cur.clearTargetX(); + cur.macroModeClose(); + if (cur.pos() != 0 && cur.openable(cur.prevAtom())) { + cur.posLeft(); + cur.push(*cur.nextAtom().nucleus()); + cur.inset().idxLast(cur); + } else if (cur.posLeft() || idxLeft(cur) + || cur.popLeft() || cur.selection()) + ; + else { + cmd = FuncRequest(LFUN_FINISHED_LEFT); + cur.undispatched(); + } + break; + + case LFUN_UP: + cur.updateFlags(Update::Decoration | Update::FitCursor); + case LFUN_UP_SELECT: + // FIXME Tried to use clearTargetX and macroModeClose, crashed on cur.up() + if (cur.inMacroMode()) { + // Make Helge happy + cur.macroModeClose(); + break; + } + cur.selHandle(cmd.action == LFUN_UP_SELECT); + if (!cur.up()) { + cmd = FuncRequest(LFUN_FINISHED_UP); + cur.undispatched(); + } + // fixes bug 1598. Please check! + cur.normalize(); + break; + + case LFUN_DOWN: + cur.updateFlags(Update::Decoration | Update::FitCursor); + case LFUN_DOWN_SELECT: + if (cur.inMacroMode()) { + cur.macroModeClose(); + break; + } + cur.selHandle(cmd.action == LFUN_DOWN_SELECT); + if (!cur.down()) { + cmd = FuncRequest(LFUN_FINISHED_DOWN); + cur.undispatched(); + } + // fixes bug 1598. Please check! + cur.normalize(); + break; + + case LFUN_MOUSE_DOUBLE: + case LFUN_MOUSE_TRIPLE: + case LFUN_WORD_SELECT: + cur.pos() = 0; + cur.idx() = 0; + cur.resetAnchor(); + cur.selection() = true; + cur.pos() = cur.lastpos(); + cur.idx() = cur.lastidx(); + cap::saveSelection(cur); + break; + + case LFUN_PARAGRAPH_UP: + case LFUN_PARAGRAPH_DOWN: + cur.updateFlags(Update::Decoration | Update::FitCursor); + case LFUN_PARAGRAPH_UP_SELECT: + case LFUN_PARAGRAPH_DOWN_SELECT: + break; + + case LFUN_LINE_BEGIN: + case LFUN_WORD_BACKWARD: + cur.updateFlags(Update::Decoration | Update::FitCursor); + case LFUN_LINE_BEGIN_SELECT: + case LFUN_WORD_BACKWARD_SELECT: + cur.selHandle(cmd.action == LFUN_WORD_BACKWARD_SELECT || + cmd.action == LFUN_LINE_BEGIN_SELECT); + cur.macroModeClose(); + if (cur.pos() != 0) { + cur.pos() = 0; + } else if (cur.col() != 0) { + cur.idx() -= cur.col(); + cur.pos() = 0; + } else if (cur.idx() != 0) { + cur.idx() = 0; + cur.pos() = 0; + } else { + cmd = FuncRequest(LFUN_FINISHED_LEFT); + cur.undispatched(); + } + break; + + case LFUN_WORD_FORWARD: + case LFUN_LINE_END: + cur.updateFlags(Update::Decoration | Update::FitCursor); + case LFUN_WORD_FORWARD_SELECT: + case LFUN_LINE_END_SELECT: + cur.selHandle(cmd.action == LFUN_WORD_FORWARD_SELECT || + cmd.action == LFUN_LINE_END_SELECT); + cur.macroModeClose(); + cur.clearTargetX(); + if (cur.pos() != cur.lastpos()) { + cur.pos() = cur.lastpos(); + } else if (ncols() && (cur.col() != cur.lastcol())) { + cur.idx() = cur.idx() - cur.col() + cur.lastcol(); + cur.pos() = cur.lastpos(); + } else if (cur.idx() != cur.lastidx()) { + cur.idx() = cur.lastidx(); + cur.pos() = cur.lastpos(); + } else { + cmd = FuncRequest(LFUN_FINISHED_RIGHT); + cur.undispatched(); + } + break; + + case LFUN_SCREEN_UP_SELECT: + case LFUN_SCREEN_UP: + cmd = FuncRequest(LFUN_FINISHED_LEFT); + cur.undispatched(); + break; + + case LFUN_SCREEN_DOWN_SELECT: + case LFUN_SCREEN_DOWN: + cmd = FuncRequest(LFUN_FINISHED_RIGHT); + cur.undispatched(); + break; + + case LFUN_CELL_FORWARD: + cur.updateFlags(Update::Decoration | Update::FitCursor); + cur.inset().idxNext(cur); + break; + + case LFUN_CELL_BACKWARD: + cur.updateFlags(Update::Decoration | Update::FitCursor); + cur.inset().idxPrev(cur); + break; + + case LFUN_WORD_DELETE_BACKWARD: + case LFUN_CHAR_DELETE_BACKWARD: + if (cur.pos() == 0) + // May affect external cell: + recordUndoInset(cur, Undo::ATOMIC); + else + recordUndo(cur, Undo::ATOMIC); + // if the inset can not be removed from within, delete it + if (!cur.backspace()) { + FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD); + cur.innerText()->dispatch(cur, cmd); + } + break; + + case LFUN_WORD_DELETE_FORWARD: + case LFUN_CHAR_DELETE_FORWARD: + if (cur.pos() == cur.lastpos()) + // May affect external cell: + recordUndoInset(cur, Undo::ATOMIC); + else + recordUndo(cur, Undo::ATOMIC); + // if the inset can not be removed from within, delete it + if (!cur.erase()) { + FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD); + cur.innerText()->dispatch(cur, cmd); + } + break; + + case LFUN_ESCAPE: + if (cur.selection()) + cur.clearSelection(); + else { + cmd = FuncRequest(LFUN_FINISHED_RIGHT); + cur.undispatched(); + } + break; + + case LFUN_INSET_TOGGLE: + recordUndo(cur); + lock(!lock()); + cur.popRight(); + break; + + case LFUN_SELF_INSERT: + if (cmd.argument().size() != 1) { + recordUndo(cur); + docstring const arg = cmd.argument(); + if (!interpretString(cur, arg)) + cur.insert(arg); + break; + } + // Don't record undo steps if we are in macro mode and + // cmd.argument is the next character of the macro name. + // Otherwise we'll get an invalid cursor if we undo after + // the macro was finished and the macro is a known command, + // e.g. sqrt. LCursor::macroModeClose replaces in this case + // the InsetMathUnknown with name "frac" by an empty + // InsetMathFrac -> a pos value > 0 is invalid. + // A side effect is that an undo before the macro is finished + // undoes the complete macro, not only the last character. + if (!cur.inMacroMode()) + recordUndo(cur); + + // spacial handling of space. If we insert an inset + // via macro mode, we want to put the cursor inside it + // if relevant. Think typing "\frac". + if (cmd.argument()[0] == ' ' + && cur.inMacroMode() && cur.macroName() != "\\" + && cur.macroModeClose()) { + MathAtom const atom = cur.prevAtom(); + if (atom->asNestInset() && atom->nargs() > 0) { + cur.posLeft(); + cur.pushLeft(*cur.nextInset()); + } + } else if (!interpretChar(cur, cmd.argument()[0])) { + cmd = FuncRequest(LFUN_FINISHED_RIGHT); + cur.undispatched(); + } + break; + + //case LFUN_SERVER_GET_XY: + // sprintf(dispatch_buffer, "%d %d",); + // break; + + case LFUN_SERVER_SET_XY: { + lyxerr << "LFUN_SERVER_SET_XY broken!" << endl; + int x = 0; + int y = 0; + istringstream is(to_utf8(cmd.argument())); + is >> x >> y; + cur.setScreenPos(x, y); + break; + } + + // Special casing for superscript in case of LyX handling + // dead-keys: + case LFUN_ACCENT_CIRCUMFLEX: + if (cmd.argument().empty()) { + // do superscript if LyX handles + // deadkeys + recordUndo(cur, Undo::ATOMIC); + script(cur, true, grabAndEraseSelection(cur)); + } + break; + + case LFUN_ACCENT_UMLAUT: + case LFUN_ACCENT_ACUTE: + case LFUN_ACCENT_GRAVE: + case LFUN_ACCENT_BREVE: + case LFUN_ACCENT_DOT: + case LFUN_ACCENT_MACRON: + case LFUN_ACCENT_CARON: + case LFUN_ACCENT_TILDE: + case LFUN_ACCENT_CEDILLA: + case LFUN_ACCENT_CIRCLE: + case LFUN_ACCENT_UNDERDOT: + case LFUN_ACCENT_TIE: + case LFUN_ACCENT_OGONEK: + case LFUN_ACCENT_HUNGARIAN_UMLAUT: + break; + + // Math fonts + case LFUN_FONT_FREE_APPLY: + case LFUN_FONT_FREE_UPDATE: + handleFont2(cur, cmd.argument()); + break; + + case LFUN_FONT_BOLD: + if (currentMode() == TEXT_MODE) + handleFont(cur, cmd.argument(), "textbf"); + else + handleFont(cur, cmd.argument(), "mathbf"); + break; + case LFUN_FONT_SANS: + if (currentMode() == TEXT_MODE) + handleFont(cur, cmd.argument(), "textsf"); + else + handleFont(cur, cmd.argument(), "mathsf"); + break; + case LFUN_FONT_EMPH: + if (currentMode() == TEXT_MODE) + handleFont(cur, cmd.argument(), "emph"); + else + handleFont(cur, cmd.argument(), "mathcal"); + break; + case LFUN_FONT_ROMAN: + if (currentMode() == TEXT_MODE) + handleFont(cur, cmd.argument(), "textrm"); + else + handleFont(cur, cmd.argument(), "mathrm"); + break; + case LFUN_FONT_CODE: + if (currentMode() == TEXT_MODE) + handleFont(cur, cmd.argument(), "texttt"); + else + handleFont(cur, cmd.argument(), "mathtt"); + break; + case LFUN_FONT_FRAK: + handleFont(cur, cmd.argument(), "mathfrak"); + break; + case LFUN_FONT_ITAL: + if (currentMode() == TEXT_MODE) + handleFont(cur, cmd.argument(), "textit"); + else + handleFont(cur, cmd.argument(), "mathit"); + break; + case LFUN_FONT_NOUN: + if (currentMode() == TEXT_MODE) + // FIXME: should be "noun" + handleFont(cur, cmd.argument(), "textsc"); + else + handleFont(cur, cmd.argument(), "mathbb"); + break; + /* + case LFUN_FONT_FREE_APPLY: + handleFont(cur, cmd.argument(), "textrm"); + break; + */ + case LFUN_FONT_DEFAULT: + handleFont(cur, cmd.argument(), "textnormal"); + break; + + case LFUN_MATH_MODE: { +#if 1 + // ignore math-mode on when already in math mode + if (currentMode() == InsetBase::MATH_MODE && cmd.argument() == "on") + break; + cur.macroModeClose(); + docstring const save_selection = grabAndEraseSelection(cur); + selClearOrDel(cur); + //cur.plainInsert(MathAtom(new InsetMathMBox(cur.bv()))); + cur.plainInsert(MathAtom(new InsetMathBox(from_ascii("mbox")))); + cur.posLeft(); + cur.pushLeft(*cur.nextInset()); + cur.niceInsert(save_selection); +#else + if (currentMode() == InsetBase::TEXT_MODE) { + cur.niceInsert(MathAtom(new InsetMathHull("simple"))); + cur.message(_("create new math text environment ($...$)")); + } else { + handleFont(cur, cmd.argument(), "textrm"); + cur.message(_("entered math text mode (textrm)")); + } +#endif + break; + } + + case LFUN_MATH_SIZE: +#if 0 + recordUndo(cur); + cur.setSize(arg); +#endif + break; + + case LFUN_MATH_MATRIX: { + recordUndo(cur, Undo::ATOMIC); + unsigned int m = 1; + unsigned int n = 1; + docstring v_align; + docstring h_align; + idocstringstream is(cmd.argument()); + is >> m >> n >> v_align >> h_align; + if (m < 1) + m = 1; + if (n < 1) + n = 1; + v_align += 'c'; + cur.niceInsert( + MathAtom(new InsetMathArray(from_ascii("array"), m, n, (char)v_align[0], h_align))); + break; + } + + case LFUN_MATH_DELIM: { + docstring ls; + docstring rs = support::split(cmd.argument(), ls, ' '); + // Reasonable default values + if (ls.empty()) + ls = '('; + if (rs.empty()) + rs = ')'; + recordUndo(cur, Undo::ATOMIC); + cur.handleNest(MathAtom(new InsetMathDelim(ls, rs))); + break; + } + + case LFUN_MATH_BIGDELIM: { + docstring const lname = from_utf8(cmd.getArg(0)); + docstring const ldelim = from_utf8(cmd.getArg(1)); + docstring const rname = from_utf8(cmd.getArg(2)); + docstring const rdelim = from_utf8(cmd.getArg(3)); + latexkeys const * l = in_word_set(lname); + bool const have_l = l && l->inset == "big" && + InsetMathBig::isBigInsetDelim(ldelim); + l = in_word_set(rname); + bool const have_r = l && l->inset == "big" && + InsetMathBig::isBigInsetDelim(rdelim); + // We mimic LFUN_MATH_DELIM in case we have an empty left + // or right delimiter. + if (have_l || have_r) { + recordUndo(cur, Undo::ATOMIC); + docstring const selection = grabAndEraseSelection(cur); + selClearOrDel(cur); + if (have_l) + cur.insert(MathAtom(new InsetMathBig(lname, + ldelim))); + cur.niceInsert(selection); + if (have_r) + cur.insert(MathAtom(new InsetMathBig(rname, + rdelim))); + } + // Don't call cur.undispatched() if we did nothing, this would + // lead to infinite recursion via LyXText::dispatch(). + break; + } + + case LFUN_SPACE_INSERT: + case LFUN_MATH_SPACE: + recordUndo(cur, Undo::ATOMIC); + cur.insert(MathAtom(new InsetMathSpace(from_ascii(",")))); + break; + + case LFUN_ERT_INSERT: + // interpret this as if a backslash was typed + recordUndo(cur, Undo::ATOMIC); + interpretChar(cur, '\\'); + break; + + case LFUN_MATH_SUBSCRIPT: + // interpret this as if a _ was typed + recordUndo(cur, Undo::ATOMIC); + interpretChar(cur, '_'); + break; + + case LFUN_MATH_SUPERSCRIPT: + // interpret this as if a ^ was typed + recordUndo(cur, Undo::ATOMIC); + interpretChar(cur, '^'); + break; + + case LFUN_QUOTE_INSERT: + // interpret this as if a straight " was typed + recordUndo(cur, Undo::ATOMIC); + interpretChar(cur, '\"'); + break; + +// FIXME: We probably should swap parts of "math-insert" and "self-insert" +// handling such that "self-insert" works on "arbitrary stuff" too, and +// math-insert only handles special math things like "matrix". + case LFUN_MATH_INSERT: { + recordUndo(cur, Undo::ATOMIC); + if (cmd.argument() == "^" || cmd.argument() == "_") { + interpretChar(cur, cmd.argument()[0]); + } else + cur.niceInsert(cmd.argument()); + break; + } + + case LFUN_DIALOG_SHOW_NEW_INSET: { + docstring const & name = cmd.argument(); + string data; + if (name == "ref") { + RefInset tmp(name); + data = tmp.createDialogStr(to_utf8(name)); + } + cur.bv().showInsetDialog(to_utf8(name), data, 0); + break; + } + + case LFUN_INSET_INSERT: { + MathArray ar; + if (createInsetMath_fromDialogStr(cmd.argument(), ar)) { + recordUndo(cur); + cur.insert(ar); + } else + cur.undispatched(); + break; + } + + default: + InsetMathDim::doDispatch(cur, cmd); + break; + } +} + + +bool InsetMathNest::getStatus(LCursor & cur, FuncRequest const & cmd, + FuncStatus & flag) const +{ + // the font related toggles + //string tc = "mathnormal"; + bool ret = true; + string const arg = to_utf8(cmd.argument()); + switch (cmd.action) { + case LFUN_TABULAR_FEATURE: + flag.enabled(false); + break; +#if 0 + case LFUN_TABULAR_FEATURE: + // FIXME: check temporarily disabled + // valign code + char align = mathcursor::valign(); + if (align == '\0') { + enable = false; + break; + } + if (cmd.argument().empty()) { + flag.clear(); + break; + } + if (!contains("tcb", cmd.argument()[0])) { + enable = false; + break; + } + flag.setOnOff(cmd.argument()[0] == align); + break; +#endif + /// We have to handle them since 1.4 blocks all unhandled actions + case LFUN_FONT_ITAL: + case LFUN_FONT_BOLD: + case LFUN_FONT_SANS: + case LFUN_FONT_EMPH: + case LFUN_FONT_CODE: + case LFUN_FONT_NOUN: + case LFUN_FONT_ROMAN: + case LFUN_FONT_DEFAULT: + flag.enabled(true); + break; + case LFUN_MATH_MUTATE: + //flag.setOnOff(mathcursor::formula()->hullType() == to_utf8(cmd.argument())); + flag.setOnOff(false); + break; + + // we just need to be in math mode to enable that + case LFUN_MATH_SIZE: + case LFUN_MATH_SPACE: + case LFUN_MATH_LIMITS: + case LFUN_MATH_NONUMBER: + case LFUN_MATH_NUMBER: + case LFUN_MATH_EXTERN: + flag.enabled(true); + break; + + case LFUN_FONT_FRAK: + flag.enabled(currentMode() != TEXT_MODE); + break; + + case LFUN_MATH_INSERT: { + bool const textarg = + arg == "\\textbf" || arg == "\\textsf" || + arg == "\\textrm" || arg == "\\textmd" || + arg == "\\textit" || arg == "\\textsc" || + arg == "\\textsl" || arg == "\\textup" || + arg == "\\texttt" || arg == "\\textbb" || + arg == "\\textnormal"; + flag.enabled(currentMode() != TEXT_MODE || textarg); + break; + } + + case LFUN_MATH_MATRIX: + flag.enabled(currentMode() == MATH_MODE); + break; + + case LFUN_INSET_INSERT: { + // Don't test createMathInset_fromDialogStr(), since + // getStatus is not called with a valid reference and the + // dialog would not be applyable. + string const name = cmd.getArg(0); + flag.enabled(name == "ref"); + break; + } + + case LFUN_MATH_DELIM: + case LFUN_MATH_BIGDELIM: + // Don't do this with multi-cell selections + flag.enabled(cur.selBegin().idx() == cur.selEnd().idx()); + break; + + default: + ret = false; + break; + } + return ret; +} + + +void InsetMathNest::edit(LCursor & cur, bool left) +{ + cur.push(*this); + cur.idx() = left ? 0 : cur.lastidx(); + cur.pos() = left ? 0 : cur.lastpos(); + cur.resetAnchor(); + //lyxerr << "InsetMathNest::edit, cur:\n" << cur << endl; +} + + +InsetBase * InsetMathNest::editXY(LCursor & cur, int x, int y) +{ + int idx_min = 0; + int dist_min = 1000000; + for (idx_type i = 0, n = nargs(); i != n; ++i) { + int const d = cell(i).dist(cur.bv(), x, y); + if (d < dist_min) { + dist_min = d; + idx_min = i; + } + } + MathArray & ar = cell(idx_min); + cur.push(*this); + cur.idx() = idx_min; + cur.pos() = ar.x2pos(x - ar.xo(cur.bv())); + + //lyxerr << "found cell : " << idx_min << " pos: " << cur.pos() << endl; + if (dist_min == 0) { + // hit inside cell + for (pos_type i = 0, n = ar.size(); i < n; ++i) + if (ar[i]->covers(cur.bv(), x, y)) + return ar[i].nucleus()->editXY(cur, x, y); + } + return this; +} + + +void InsetMathNest::lfunMousePress(LCursor & cur, FuncRequest & cmd) +{ + //lyxerr << "## lfunMousePress: buttons: " << cmd.button() << endl; + BufferView & bv = cur.bv(); + if (cmd.button() == mouse_button::button1) { + //lyxerr << "## lfunMousePress: setting cursor to: " << cur << endl; + bv.mouseSetCursor(cur); + // Update the cursor update flags as needed: + // + // Update::Decoration: tells to update the decoration (visual box + // corners that define the inset)/ + // Update::FitCursor: adjust the screen to the cursor position if + // needed + // cur.result().update(): don't overwrite previously set flags. + cur.updateFlags(Update::Decoration | Update::FitCursor | cur.result().update()); + } else if (cmd.button() == mouse_button::button2) { + MathArray ar; + if (cap::selection()) { + // See comment in LyXText::dispatch why we do this + cap::copySelectionToStack(); + cmd = FuncRequest(LFUN_PASTE, "0"); + doDispatch(cur, cmd); + } else + asArray(theSelection().get(), ar); + + cur.insert(ar); + bv.mouseSetCursor(cur); + } +} + + +void InsetMathNest::lfunMouseMotion(LCursor & cur, FuncRequest & cmd) +{ + // only select with button 1 + if (cmd.button() == mouse_button::button1) { + LCursor & bvcur = cur.bv().cursor(); + if (bvcur.anchor_.hasPart(cur)) { + //lyxerr << "## lfunMouseMotion: cursor: " << cur << endl; + bvcur.setCursor(cur); + bvcur.selection() = true; + //lyxerr << "MOTION " << bvcur << endl; + } else + cur.undispatched(); + } +} + + +void InsetMathNest::lfunMouseRelease(LCursor & cur, FuncRequest & cmd) +{ + //lyxerr << "## lfunMouseRelease: buttons: " << cmd.button() << endl; + + if (cmd.button() == mouse_button::button1) { + if (!cur.selection()) + cur.noUpdate(); + else { + LCursor & bvcur = cur.bv().cursor(); + bvcur.selection() = true; + cap::saveSelection(bvcur); + } + return; + } + + cur.undispatched(); +} + + +bool InsetMathNest::interpretChar(LCursor & cur, char_type c) +{ + //lyxerr << "interpret 2: '" << c << "'" << endl; + docstring save_selection; + if (c == '^' || c == '_') + save_selection = grabAndEraseSelection(cur); + + cur.clearTargetX(); + + // handle macroMode + if (cur.inMacroMode()) { + docstring name = cur.macroName(); + + /// are we currently typing '#1' or '#2' or...? + if (name == "\\#") { + cur.backspace(); + int n = c - '0'; + if (n >= 1 && n <= 9) + cur.insert(new MathMacroArgument(n)); + return true; + } + + if (isAlphaASCII(c)) { + cur.activeMacro()->setName(name + docstring(1, c)); + return true; + } + + // handle 'special char' macros + if (name == "\\") { + // remove the '\\' + if (c == '\\') { + cur.backspace(); + if (currentMode() == InsetMath::TEXT_MODE) + cur.niceInsert(createInsetMath("textbackslash")); + else + cur.niceInsert(createInsetMath("backslash")); + } else if (c == '{') { + cur.backspace(); + cur.niceInsert(MathAtom(new InsetMathBrace)); + } else if (c == '%') { + cur.backspace(); + cur.niceInsert(MathAtom(new InsetMathComment)); + } else if (c == '#') { + BOOST_ASSERT(cur.activeMacro()); + cur.activeMacro()->setName(name + docstring(1, c)); + } else { + cur.backspace(); + cur.niceInsert(createInsetMath(docstring(1, c))); + } + return true; + } + + // One character big delimiters. The others are handled in + // interpretString(). + latexkeys const * l = in_word_set(name.substr(1)); + if (name[0] == '\\' && l && l->inset == "big") { + docstring delim; + switch (c) { + case '{': + delim = from_ascii("\\{"); + break; + case '}': + delim = from_ascii("\\}"); + break; + default: + delim = docstring(1, c); + break; + } + if (InsetMathBig::isBigInsetDelim(delim)) { + // name + delim ared a valid InsetMathBig. + // We can't use cur.macroModeClose() because + // it does not handle delim. + InsetMathUnknown * p = cur.activeMacro(); + p->finalize(); + --cur.pos(); + cur.cell().erase(cur.pos()); + cur.plainInsert(MathAtom( + new InsetMathBig(name.substr(1), delim))); + return true; + } + } + + // leave macro mode and try again if necessary + cur.macroModeClose(); + if (c == '{') + cur.niceInsert(MathAtom(new InsetMathBrace)); + else if (c != ' ') + interpretChar(cur, c); + return true; + } + + // This is annoying as one has to press far too often. + // Disable it. + +#if 0 + // leave autocorrect mode if necessary + if (autocorrect() && c == ' ') { + autocorrect() = false; + return true; + } +#endif + + // just clear selection on pressing the space bar + if (cur.selection() && c == ' ') { + cur.selection() = false; + return true; + } + + selClearOrDel(cur); + + if (c == '\\') { + //lyxerr << "starting with macro" << endl; + cur.insert(MathAtom(new InsetMathUnknown(from_ascii("\\"), false))); + return true; + } + + if (c == '\n') { + if (currentMode() == InsetMath::TEXT_MODE) + cur.insert(c); + return true; + } + + if (c == ' ') { + if (currentMode() == InsetMath::TEXT_MODE) { + // insert spaces in text mode, + // but suppress direct insertion of two spaces in a row + // the still allows typing 'a' and deleting the 'a', but + // it is better than nothing... + if (!cur.pos() != 0 || cur.prevAtom()->getChar() != ' ') { + cur.insert(c); + // FIXME: we have to enable full redraw here because of the + // visual box corners that define the inset. If we know for + // sure that we stay within the same cell we can optimize for + // that using: + //cur.updateFlags(Update::SinglePar | Update::FitCursor); + } + return true; + } + if (cur.pos() != 0 && cur.prevAtom()->asSpaceInset()) { + cur.prevAtom().nucleus()->asSpaceInset()->incSpace(); + // FIXME: we have to enable full redraw here because of the + // visual box corners that define the inset. If we know for + // sure that we stay within the same cell we can optimize for + // that using: + //cur.updateFlags(Update::SinglePar | Update::FitCursor); + return true; + } + + if (cur.popRight()) { + // FIXME: we have to enable full redraw here because of the + // visual box corners that define the inset. If we know for + // sure that we stay within the same cell we can optimize for + // that using: + //cur.updateFlags(Update::FitCursor); + return true; + } + + // if we are at the very end, leave the formula + return cur.pos() != cur.lastpos(); + } + + // These shouldn't work in text mode: + if (currentMode() != InsetMath::TEXT_MODE) { + if (c == '_') { + script(cur, false, save_selection); + return true; + } + if (c == '^') { + script(cur, true, save_selection); + return true; + } + if (c == '~') { + cur.niceInsert(createInsetMath("sim")); + return true; + } + } + + if (c == '{' || c == '}' || c == '&' || c == '$' || c == '#' || + c == '%' || c == '_' || c == '^') { + cur.niceInsert(createInsetMath(docstring(1, c))); + return true; + } + + + // try auto-correction + //if (autocorrect() && hasPrevAtom() && math_autocorrect(prevAtom(), c)) + // return true; + + // no special circumstances, so insert the character without any fuss + cur.insert(c); + cur.autocorrect() = true; + return true; +} + + +bool InsetMathNest::interpretString(LCursor & cur, docstring const & str) +{ + // Create a InsetMathBig from cur.cell()[cur.pos() - 1] and t if + // possible + if (!cur.empty() && cur.pos() > 0 && + cur.cell()[cur.pos() - 1]->asUnknownInset()) { + if (InsetMathBig::isBigInsetDelim(str)) { + docstring prev = asString(cur.cell()[cur.pos() - 1]); + if (prev[0] == '\\') { + prev = prev.substr(1); + latexkeys const * l = in_word_set(prev); + if (l && l->inset == "big") { + cur.cell()[cur.pos() - 1] = + MathAtom(new InsetMathBig(prev, str)); + return true; + } + } + } + } + return false; +} + + +bool InsetMathNest::script(LCursor & cur, bool up, + docstring const & save_selection) +{ + // Hack to get \^ and \_ working + //lyxerr << "handling script: up: " << up << endl; + if (cur.inMacroMode() && cur.macroName() == "\\") { + if (up) + cur.niceInsert(createInsetMath("mathcircumflex")); + else + interpretChar(cur, '_'); + return true; + } + + cur.macroModeClose(); + if (asScriptInset() && cur.idx() == 0) { + // we are in a nucleus of a script inset, move to _our_ script + InsetMathScript * inset = asScriptInset(); + //lyxerr << " going to cell " << inset->idxOfScript(up) << endl; + inset->ensure(up); + cur.idx() = inset->idxOfScript(up); + cur.pos() = 0; + } else if (cur.pos() != 0 && cur.prevAtom()->asScriptInset()) { + --cur.pos(); + InsetMathScript * inset = cur.nextAtom().nucleus()->asScriptInset(); + cur.push(*inset); + inset->ensure(up); + cur.idx() = inset->idxOfScript(up); + cur.pos() = cur.lastpos(); + } else { + // convert the thing to our left to a scriptinset or create a new + // one if in the very first position of the array + if (cur.pos() == 0) { + //lyxerr << "new scriptinset" << endl; + cur.insert(new InsetMathScript(up)); + } else { + //lyxerr << "converting prev atom " << endl; + cur.prevAtom() = MathAtom(new InsetMathScript(cur.prevAtom(), up)); + } + --cur.pos(); + InsetMathScript * inset = cur.nextAtom().nucleus()->asScriptInset(); + // See comment in MathParser.cpp for special handling of {}-bases + + cur.push(*inset); + cur.idx() = 1; + cur.pos() = 0; + } + //lyxerr << "inserting selection 1:\n" << save_selection << endl; + cur.niceInsert(save_selection); + cur.resetAnchor(); + //lyxerr << "inserting selection 2:\n" << save_selection << endl; + return true; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathNumber.C b/src/mathed/InsetMathNumber.C deleted file mode 100644 index 0a56cb01e9..0000000000 --- a/src/mathed/InsetMathNumber.C +++ /dev/null @@ -1,88 +0,0 @@ -/** - * \file InsetMathNumber.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathNumber.h" -#include "MathStream.h" -#include "MathStream.h" -#include "MathSupport.h" - - -namespace lyx { - -using std::string; -using std::auto_ptr; -using std::vector; - -InsetMathNumber::InsetMathNumber(docstring const & s) - : str_(s) -{} - - -auto_ptr InsetMathNumber::doClone() const -{ - return auto_ptr(new InsetMathNumber(*this)); -} - - -bool InsetMathNumber::metrics(MetricsInfo & mi, Dimension & dim) const -{ - mathed_string_dim(mi.base.font, str_, dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathNumber::draw(PainterInfo & pi, int x, int y) const -{ - pi.draw(x, y, str_); -} - - -void InsetMathNumber::normalize(NormalStream & os) const -{ - os << "[number " << str_ << ']'; -} - - -void InsetMathNumber::maple(MapleStream & os) const -{ - os << str_; -} - - -void InsetMathNumber::mathematica(MathematicaStream & os) const -{ - os << str_; -} - - -void InsetMathNumber::octave(OctaveStream & os) const -{ - os << str_; -} - - -void InsetMathNumber::mathmlize(MathStream & os) const -{ - os << " " << str_ << " "; -} - - -void InsetMathNumber::write(WriteStream & os) const -{ - os << str_; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathNumber.cpp b/src/mathed/InsetMathNumber.cpp new file mode 100644 index 0000000000..0a56cb01e9 --- /dev/null +++ b/src/mathed/InsetMathNumber.cpp @@ -0,0 +1,88 @@ +/** + * \file InsetMathNumber.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathNumber.h" +#include "MathStream.h" +#include "MathStream.h" +#include "MathSupport.h" + + +namespace lyx { + +using std::string; +using std::auto_ptr; +using std::vector; + +InsetMathNumber::InsetMathNumber(docstring const & s) + : str_(s) +{} + + +auto_ptr InsetMathNumber::doClone() const +{ + return auto_ptr(new InsetMathNumber(*this)); +} + + +bool InsetMathNumber::metrics(MetricsInfo & mi, Dimension & dim) const +{ + mathed_string_dim(mi.base.font, str_, dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathNumber::draw(PainterInfo & pi, int x, int y) const +{ + pi.draw(x, y, str_); +} + + +void InsetMathNumber::normalize(NormalStream & os) const +{ + os << "[number " << str_ << ']'; +} + + +void InsetMathNumber::maple(MapleStream & os) const +{ + os << str_; +} + + +void InsetMathNumber::mathematica(MathematicaStream & os) const +{ + os << str_; +} + + +void InsetMathNumber::octave(OctaveStream & os) const +{ + os << str_; +} + + +void InsetMathNumber::mathmlize(MathStream & os) const +{ + os << " " << str_ << " "; +} + + +void InsetMathNumber::write(WriteStream & os) const +{ + os << str_; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathOverset.C b/src/mathed/InsetMathOverset.C deleted file mode 100644 index 2157a62368..0000000000 --- a/src/mathed/InsetMathOverset.C +++ /dev/null @@ -1,95 +0,0 @@ -/** - * \file InsetMathOverset.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathOverset.h" -#include "MathData.h" -#include "MathStream.h" - -#include "cursor.h" -#include "LaTeXFeatures.h" - - -namespace lyx { - -using std::max; -using std::auto_ptr; - - -auto_ptr InsetMathOverset::doClone() const -{ - return auto_ptr(new InsetMathOverset(*this)); -} - - -bool InsetMathOverset::metrics(MetricsInfo & mi, Dimension & dim) const -{ - cell(1).metrics(mi); - FracChanger dummy(mi.base); - cell(0).metrics(mi); - dim.wid = max(cell(0).width(), cell(1).width()) + 4; - dim.asc = cell(1).ascent() + cell(0).height() + 4; - dim.des = cell(1).descent(); - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathOverset::draw(PainterInfo & pi, int x, int y) const -{ - int m = x + width() / 2; - int yo = y - cell(1).ascent() + cell(0).descent() - 1; - cell(1).draw(pi, m - cell(1).width() / 2, y); - FracChanger dummy(pi.base); - cell(0).draw(pi, m - cell(0).width() / 2, yo); - drawMarkers(pi, x, y); -} - - -bool InsetMathOverset::idxFirst(LCursor & cur) const -{ - cur.idx() = 1; - cur.pos() = 0; - return true; -} - - -bool InsetMathOverset::idxLast(LCursor & cur) const -{ - cur.idx() = 1; - cur.pos() = cur.lastpos(); - return true; -} - - -void InsetMathOverset::write(WriteStream & os) const -{ - os << "\\overset{" << cell(0) << "}{" << cell(1) << '}'; -} - - -void InsetMathOverset::normalize(NormalStream & os) const -{ - os << "[overset " << cell(0) << ' ' << cell(1) << ']'; -} - - -void InsetMathOverset::validate(LaTeXFeatures & features) const -{ - features.require("amsmath"); - InsetMathNest::validate(features); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathOverset.cpp b/src/mathed/InsetMathOverset.cpp new file mode 100644 index 0000000000..2157a62368 --- /dev/null +++ b/src/mathed/InsetMathOverset.cpp @@ -0,0 +1,95 @@ +/** + * \file InsetMathOverset.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathOverset.h" +#include "MathData.h" +#include "MathStream.h" + +#include "cursor.h" +#include "LaTeXFeatures.h" + + +namespace lyx { + +using std::max; +using std::auto_ptr; + + +auto_ptr InsetMathOverset::doClone() const +{ + return auto_ptr(new InsetMathOverset(*this)); +} + + +bool InsetMathOverset::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(1).metrics(mi); + FracChanger dummy(mi.base); + cell(0).metrics(mi); + dim.wid = max(cell(0).width(), cell(1).width()) + 4; + dim.asc = cell(1).ascent() + cell(0).height() + 4; + dim.des = cell(1).descent(); + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathOverset::draw(PainterInfo & pi, int x, int y) const +{ + int m = x + width() / 2; + int yo = y - cell(1).ascent() + cell(0).descent() - 1; + cell(1).draw(pi, m - cell(1).width() / 2, y); + FracChanger dummy(pi.base); + cell(0).draw(pi, m - cell(0).width() / 2, yo); + drawMarkers(pi, x, y); +} + + +bool InsetMathOverset::idxFirst(LCursor & cur) const +{ + cur.idx() = 1; + cur.pos() = 0; + return true; +} + + +bool InsetMathOverset::idxLast(LCursor & cur) const +{ + cur.idx() = 1; + cur.pos() = cur.lastpos(); + return true; +} + + +void InsetMathOverset::write(WriteStream & os) const +{ + os << "\\overset{" << cell(0) << "}{" << cell(1) << '}'; +} + + +void InsetMathOverset::normalize(NormalStream & os) const +{ + os << "[overset " << cell(0) << ' ' << cell(1) << ']'; +} + + +void InsetMathOverset::validate(LaTeXFeatures & features) const +{ + features.require("amsmath"); + InsetMathNest::validate(features); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathPar.C b/src/mathed/InsetMathPar.C deleted file mode 100644 index 8cc933e9a3..0000000000 --- a/src/mathed/InsetMathPar.C +++ /dev/null @@ -1,69 +0,0 @@ -/** - * \file InsetMathPar.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathPar.h" -#include "MathData.h" -#include "MathStream.h" -#include "support/std_ostream.h" - - -namespace lyx { - - -using std::auto_ptr; - - -InsetMathPar::InsetMathPar(MathArray const & ar) -{ - cells_[0] = ar; -} - - -bool InsetMathPar::metrics(MetricsInfo & mi, Dimension & dim) const -{ - dim = dim_; - FontSetChanger dummy1(mi.base, "textnormal"); - InsetMathGrid::metrics(mi); - if (dim_ == dim) - return false; - dim = dim_; - return true; -} - - -void InsetMathPar::draw(PainterInfo & pi, int x, int y) const -{ - FontSetChanger dummy1(pi.base, "textnormal"); - InsetMathGrid::draw(pi, x, y); -} - - -void InsetMathPar::write(WriteStream & os) const -{ - for (idx_type i = 0; i < nargs(); ++i) - os << cell(i) << "\n"; -} - - -void InsetMathPar::infoize(odocstream & os) const -{ - os << "Type: Paragraph "; -} - - -auto_ptr InsetMathPar::doClone() const -{ - return auto_ptr(new InsetMathPar(*this)); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathPar.cpp b/src/mathed/InsetMathPar.cpp new file mode 100644 index 0000000000..8cc933e9a3 --- /dev/null +++ b/src/mathed/InsetMathPar.cpp @@ -0,0 +1,69 @@ +/** + * \file InsetMathPar.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathPar.h" +#include "MathData.h" +#include "MathStream.h" +#include "support/std_ostream.h" + + +namespace lyx { + + +using std::auto_ptr; + + +InsetMathPar::InsetMathPar(MathArray const & ar) +{ + cells_[0] = ar; +} + + +bool InsetMathPar::metrics(MetricsInfo & mi, Dimension & dim) const +{ + dim = dim_; + FontSetChanger dummy1(mi.base, "textnormal"); + InsetMathGrid::metrics(mi); + if (dim_ == dim) + return false; + dim = dim_; + return true; +} + + +void InsetMathPar::draw(PainterInfo & pi, int x, int y) const +{ + FontSetChanger dummy1(pi.base, "textnormal"); + InsetMathGrid::draw(pi, x, y); +} + + +void InsetMathPar::write(WriteStream & os) const +{ + for (idx_type i = 0; i < nargs(); ++i) + os << cell(i) << "\n"; +} + + +void InsetMathPar::infoize(odocstream & os) const +{ + os << "Type: Paragraph "; +} + + +auto_ptr InsetMathPar::doClone() const +{ + return auto_ptr(new InsetMathPar(*this)); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathPhantom.C b/src/mathed/InsetMathPhantom.C deleted file mode 100644 index e4374dce2e..0000000000 --- a/src/mathed/InsetMathPhantom.C +++ /dev/null @@ -1,177 +0,0 @@ -/** - * \file InsetMathPhantom.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Georg Baum - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathPhantom.h" -#include "MathStream.h" -#include "MathStream.h" - -#include "LColor.h" - -#include "frontends/Painter.h" - -#include "support/std_ostream.h" - - -namespace lyx { - - -InsetMathPhantom::InsetMathPhantom(Kind k) - : InsetMathNest(1), kind_(k) -{} - - -std::auto_ptr InsetMathPhantom::doClone() const -{ - return std::auto_ptr(new InsetMathPhantom(*this)); -} - - -bool InsetMathPhantom::metrics(MetricsInfo & mi, Dimension & dim) const -{ - cell(0).metrics(mi, dim); - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathPhantom::draw(PainterInfo & pi, int x, int y) const -{ - static int const arrow_size = 4; - - // We first draw the text and then an arrow - LColor_color const origcol = pi.base.font.color(); - pi.base.font.setColor(LColor::special); - cell(0).draw(pi, x + 1, y); - pi.base.font.setColor(origcol); - - if (kind_ == phantom || kind_ == vphantom) { - // y1--------- - // / \. - // y2----- / | \. - // | - // | - // y3----- \ | / - // \ / - // y4--------- - // | | | - // / | \. - // x1 x2 x3 - - int const x2 = x + dim_.wid / 2; - int const x1 = x2 - arrow_size; - int const x3 = x2 + arrow_size; - - int const y1 = y - dim_.asc; - int const y2 = y1 + arrow_size; - int const y4 = y + dim_.des; - int const y3 = y4 - arrow_size; - - // top arrow - pi.pain.line(x2, y1, x1, y2, LColor::added_space); - pi.pain.line(x2, y1, x3, y2, LColor::added_space); - - // bottom arrow - pi.pain.line(x2, y4, x1, y3, LColor::added_space); - pi.pain.line(x2, y4, x3, y3, LColor::added_space); - - // joining line - pi.pain.line(x2, y1, x2, y4, LColor::added_space); - } - - if (kind_ == phantom || kind_ == hphantom) { - // y1---- / \. - // / \. - // y2--- <----------------> - // \ / - // y3---- \ / - // | | | | - // x1 x2 x3 x4 - - int const x1 = x; - int const x2 = x + arrow_size; - int const x4 = x + dim_.wid; - int const x3 = x4 - arrow_size; - - int const y2 = y + (dim_.des - dim_.asc) / 2; - int const y1 = y2 - arrow_size; - int const y3 = y2 + arrow_size; - - // left arrow - pi.pain.line(x1, y2, x2, y3, LColor::added_space); - pi.pain.line(x1, y2, x2, y1, LColor::added_space); - - // right arrow - pi.pain.line(x4, y2, x3, y3, LColor::added_space); - pi.pain.line(x4, y2, x3, y1, LColor::added_space); - - // joining line - pi.pain.line(x1, y2, x4, y2, LColor::added_space); - } - - drawMarkers(pi, x, y); -} - - -void InsetMathPhantom::write(WriteStream & os) const -{ - switch (kind_) { - case phantom: - os << "\\phantom{"; - break; - case vphantom: - os << "\\vphantom{"; - break; - case hphantom: - os << "\\hphantom{"; - break; - } - os << cell(0) << '}'; -} - - -void InsetMathPhantom::normalize(NormalStream & os) const -{ - switch (kind_) { - case phantom: - os << "[phantom "; - break; - case vphantom: - os << "[vphantom "; - break; - case hphantom: - os << "[hphantom "; - break; - } - os << cell(0) << ']'; -} - - -void InsetMathPhantom::infoize(odocstream & os) const -{ - switch (kind_) { - case phantom: - os << "Phantom"; - break; - case vphantom: - os << "Vphantom"; - break; - case hphantom: - os << "Hphantom"; - break; - } -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathPhantom.cpp b/src/mathed/InsetMathPhantom.cpp new file mode 100644 index 0000000000..e4374dce2e --- /dev/null +++ b/src/mathed/InsetMathPhantom.cpp @@ -0,0 +1,177 @@ +/** + * \file InsetMathPhantom.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Georg Baum + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathPhantom.h" +#include "MathStream.h" +#include "MathStream.h" + +#include "LColor.h" + +#include "frontends/Painter.h" + +#include "support/std_ostream.h" + + +namespace lyx { + + +InsetMathPhantom::InsetMathPhantom(Kind k) + : InsetMathNest(1), kind_(k) +{} + + +std::auto_ptr InsetMathPhantom::doClone() const +{ + return std::auto_ptr(new InsetMathPhantom(*this)); +} + + +bool InsetMathPhantom::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(0).metrics(mi, dim); + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathPhantom::draw(PainterInfo & pi, int x, int y) const +{ + static int const arrow_size = 4; + + // We first draw the text and then an arrow + LColor_color const origcol = pi.base.font.color(); + pi.base.font.setColor(LColor::special); + cell(0).draw(pi, x + 1, y); + pi.base.font.setColor(origcol); + + if (kind_ == phantom || kind_ == vphantom) { + // y1--------- + // / \. + // y2----- / | \. + // | + // | + // y3----- \ | / + // \ / + // y4--------- + // | | | + // / | \. + // x1 x2 x3 + + int const x2 = x + dim_.wid / 2; + int const x1 = x2 - arrow_size; + int const x3 = x2 + arrow_size; + + int const y1 = y - dim_.asc; + int const y2 = y1 + arrow_size; + int const y4 = y + dim_.des; + int const y3 = y4 - arrow_size; + + // top arrow + pi.pain.line(x2, y1, x1, y2, LColor::added_space); + pi.pain.line(x2, y1, x3, y2, LColor::added_space); + + // bottom arrow + pi.pain.line(x2, y4, x1, y3, LColor::added_space); + pi.pain.line(x2, y4, x3, y3, LColor::added_space); + + // joining line + pi.pain.line(x2, y1, x2, y4, LColor::added_space); + } + + if (kind_ == phantom || kind_ == hphantom) { + // y1---- / \. + // / \. + // y2--- <----------------> + // \ / + // y3---- \ / + // | | | | + // x1 x2 x3 x4 + + int const x1 = x; + int const x2 = x + arrow_size; + int const x4 = x + dim_.wid; + int const x3 = x4 - arrow_size; + + int const y2 = y + (dim_.des - dim_.asc) / 2; + int const y1 = y2 - arrow_size; + int const y3 = y2 + arrow_size; + + // left arrow + pi.pain.line(x1, y2, x2, y3, LColor::added_space); + pi.pain.line(x1, y2, x2, y1, LColor::added_space); + + // right arrow + pi.pain.line(x4, y2, x3, y3, LColor::added_space); + pi.pain.line(x4, y2, x3, y1, LColor::added_space); + + // joining line + pi.pain.line(x1, y2, x4, y2, LColor::added_space); + } + + drawMarkers(pi, x, y); +} + + +void InsetMathPhantom::write(WriteStream & os) const +{ + switch (kind_) { + case phantom: + os << "\\phantom{"; + break; + case vphantom: + os << "\\vphantom{"; + break; + case hphantom: + os << "\\hphantom{"; + break; + } + os << cell(0) << '}'; +} + + +void InsetMathPhantom::normalize(NormalStream & os) const +{ + switch (kind_) { + case phantom: + os << "[phantom "; + break; + case vphantom: + os << "[vphantom "; + break; + case hphantom: + os << "[hphantom "; + break; + } + os << cell(0) << ']'; +} + + +void InsetMathPhantom::infoize(odocstream & os) const +{ + switch (kind_) { + case phantom: + os << "Phantom"; + break; + case vphantom: + os << "Vphantom"; + break; + case hphantom: + os << "Hphantom"; + break; + } +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathRef.C b/src/mathed/InsetMathRef.C deleted file mode 100644 index 0817fc642c..0000000000 --- a/src/mathed/InsetMathRef.C +++ /dev/null @@ -1,197 +0,0 @@ -/** - * \file InsetMathRef.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathRef.h" - -#include "BufferView.h" -#include "LaTeXFeatures.h" -#include "buffer.h" -#include "cursor.h" -#include "debug.h" -#include "funcrequest.h" -#include "FuncStatus.h" -#include "gettext.h" -#include "MathData.h" -#include "MathFactory.h" -#include "MathSupport.h" -#include "outputparams.h" -#include "sgml.h" - -#include "insets/InsetCommand.h" - - -namespace lyx { - -using std::string; -using std::auto_ptr; -using std::endl; - - -RefInset::RefInset() - : CommandInset(from_ascii("ref")) -{} - - -RefInset::RefInset(docstring const & data) - : CommandInset(data) -{} - - -auto_ptr RefInset::doClone() const -{ - return auto_ptr(new RefInset(*this)); -} - - -void RefInset::infoize(odocstream & os) const -{ - os << "Ref: " << cell(0); -} - - -void RefInset::doDispatch(LCursor & cur, FuncRequest & cmd) -{ - switch (cmd.action) { - case LFUN_INSET_MODIFY: - if (cmd.getArg(0) == "ref") { - MathArray ar; - if (createInsetMath_fromDialogStr(cmd.argument(), ar)) { - *this = *ar[0].nucleus()->asRefInset(); - break; - } - } - cur.undispatched(); - break; - - case LFUN_INSET_DIALOG_UPDATE: { - string const data = createDialogStr("ref"); - cur.bv().updateDialog("ref", data); - break; - } - - case LFUN_MOUSE_RELEASE: - if (cmd.button() == mouse_button::button3) { - lyxerr << "trying to goto ref '" << to_utf8(asString(cell(0))) << "'" << endl; - cur.bv().dispatch(FuncRequest(LFUN_LABEL_GOTO, asString(cell(0)))); - break; - } - if (cmd.button() == mouse_button::button1) { - // Eventually trigger dialog with button 3, not 1 - string const data = createDialogStr("ref"); - cur.bv().showInsetDialog("ref", data, this); - break; - } - cur.undispatched(); - break; - - case LFUN_MOUSE_PRESS: - case LFUN_MOUSE_MOTION: - // eat other mouse commands - break; - - default: - CommandInset::doDispatch(cur, cmd); - break; - } -} - - -bool RefInset::getStatus(LCursor & cur, FuncRequest const & cmd, - FuncStatus & status) const -{ - switch (cmd.action) { - // we handle these - case LFUN_INSET_MODIFY: - case LFUN_INSET_DIALOG_UPDATE: - case LFUN_MOUSE_RELEASE: - case LFUN_MOUSE_PRESS: - case LFUN_MOUSE_MOTION: - status.enabled(true); - return true; - default: - return CommandInset::getStatus(cur, cmd, status); - } -} - - -docstring const RefInset::screenLabel() const -{ - docstring str; - for (int i = 0; !types[i].latex_name.empty(); ++i) { - if (commandname() == types[i].latex_name) { - str = _(to_utf8(types[i].short_gui_name)); - break; - } - } - str += asString(cell(0)); - - //if (/* !isLatex && */ !cell(0).empty()) { - // str += "||"; - // str += asString(cell(1)); - //} - return str; -} - - -void RefInset::validate(LaTeXFeatures & features) const -{ - if (commandname() == "vref" || commandname() == "vpageref") - features.require("varioref"); - else if (commandname() == "prettyref") - features.require("prettyref"); -} - - -int RefInset::docbook(Buffer const & buf, odocstream & os, - OutputParams const & runparams) const -{ - if (cell(1).empty()) { - os << ""; - else - os << "\">"; - } else { - os << "" - << asString(cell(1)) - << ""; - } - - return 0; -} - - -string const RefInset::createDialogStr(string const & name) const -{ - InsetCommandParams icp(to_ascii(commandname())); - icp["reference"] = asString(cell(0)); - if (!cell(1).empty()) - icp["name"] = asString(cell(1)); - return InsetCommandMailer::params2string(name, icp); -} - - -RefInset::ref_type_info RefInset::types[] = { - { from_ascii("ref"), from_ascii(N_("Standard")), from_ascii(N_("Ref: "))}, - { from_ascii("eqref"), from_ascii(N_("Equation")), from_ascii(N_("EqRef: "))}, - { from_ascii("pageref"), from_ascii(N_("Page Number")), from_ascii(N_("Page: "))}, - { from_ascii("vpageref"), from_ascii(N_("Textual Page Number")), from_ascii(N_("TextPage: "))}, - { from_ascii("vref"), from_ascii(N_("Standard+Textual Page")), from_ascii(N_("Ref+Text: "))}, - { from_ascii("prettyref"), from_ascii(N_("PrettyRef")), from_ascii(N_("FormatRef: "))}, - { from_ascii(""), from_ascii(""), from_ascii("") } -}; - - -} // namespace lyx diff --git a/src/mathed/InsetMathRef.cpp b/src/mathed/InsetMathRef.cpp new file mode 100644 index 0000000000..0817fc642c --- /dev/null +++ b/src/mathed/InsetMathRef.cpp @@ -0,0 +1,197 @@ +/** + * \file InsetMathRef.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathRef.h" + +#include "BufferView.h" +#include "LaTeXFeatures.h" +#include "buffer.h" +#include "cursor.h" +#include "debug.h" +#include "funcrequest.h" +#include "FuncStatus.h" +#include "gettext.h" +#include "MathData.h" +#include "MathFactory.h" +#include "MathSupport.h" +#include "outputparams.h" +#include "sgml.h" + +#include "insets/InsetCommand.h" + + +namespace lyx { + +using std::string; +using std::auto_ptr; +using std::endl; + + +RefInset::RefInset() + : CommandInset(from_ascii("ref")) +{} + + +RefInset::RefInset(docstring const & data) + : CommandInset(data) +{} + + +auto_ptr RefInset::doClone() const +{ + return auto_ptr(new RefInset(*this)); +} + + +void RefInset::infoize(odocstream & os) const +{ + os << "Ref: " << cell(0); +} + + +void RefInset::doDispatch(LCursor & cur, FuncRequest & cmd) +{ + switch (cmd.action) { + case LFUN_INSET_MODIFY: + if (cmd.getArg(0) == "ref") { + MathArray ar; + if (createInsetMath_fromDialogStr(cmd.argument(), ar)) { + *this = *ar[0].nucleus()->asRefInset(); + break; + } + } + cur.undispatched(); + break; + + case LFUN_INSET_DIALOG_UPDATE: { + string const data = createDialogStr("ref"); + cur.bv().updateDialog("ref", data); + break; + } + + case LFUN_MOUSE_RELEASE: + if (cmd.button() == mouse_button::button3) { + lyxerr << "trying to goto ref '" << to_utf8(asString(cell(0))) << "'" << endl; + cur.bv().dispatch(FuncRequest(LFUN_LABEL_GOTO, asString(cell(0)))); + break; + } + if (cmd.button() == mouse_button::button1) { + // Eventually trigger dialog with button 3, not 1 + string const data = createDialogStr("ref"); + cur.bv().showInsetDialog("ref", data, this); + break; + } + cur.undispatched(); + break; + + case LFUN_MOUSE_PRESS: + case LFUN_MOUSE_MOTION: + // eat other mouse commands + break; + + default: + CommandInset::doDispatch(cur, cmd); + break; + } +} + + +bool RefInset::getStatus(LCursor & cur, FuncRequest const & cmd, + FuncStatus & status) const +{ + switch (cmd.action) { + // we handle these + case LFUN_INSET_MODIFY: + case LFUN_INSET_DIALOG_UPDATE: + case LFUN_MOUSE_RELEASE: + case LFUN_MOUSE_PRESS: + case LFUN_MOUSE_MOTION: + status.enabled(true); + return true; + default: + return CommandInset::getStatus(cur, cmd, status); + } +} + + +docstring const RefInset::screenLabel() const +{ + docstring str; + for (int i = 0; !types[i].latex_name.empty(); ++i) { + if (commandname() == types[i].latex_name) { + str = _(to_utf8(types[i].short_gui_name)); + break; + } + } + str += asString(cell(0)); + + //if (/* !isLatex && */ !cell(0).empty()) { + // str += "||"; + // str += asString(cell(1)); + //} + return str; +} + + +void RefInset::validate(LaTeXFeatures & features) const +{ + if (commandname() == "vref" || commandname() == "vpageref") + features.require("varioref"); + else if (commandname() == "prettyref") + features.require("prettyref"); +} + + +int RefInset::docbook(Buffer const & buf, odocstream & os, + OutputParams const & runparams) const +{ + if (cell(1).empty()) { + os << ""; + else + os << "\">"; + } else { + os << "" + << asString(cell(1)) + << ""; + } + + return 0; +} + + +string const RefInset::createDialogStr(string const & name) const +{ + InsetCommandParams icp(to_ascii(commandname())); + icp["reference"] = asString(cell(0)); + if (!cell(1).empty()) + icp["name"] = asString(cell(1)); + return InsetCommandMailer::params2string(name, icp); +} + + +RefInset::ref_type_info RefInset::types[] = { + { from_ascii("ref"), from_ascii(N_("Standard")), from_ascii(N_("Ref: "))}, + { from_ascii("eqref"), from_ascii(N_("Equation")), from_ascii(N_("EqRef: "))}, + { from_ascii("pageref"), from_ascii(N_("Page Number")), from_ascii(N_("Page: "))}, + { from_ascii("vpageref"), from_ascii(N_("Textual Page Number")), from_ascii(N_("TextPage: "))}, + { from_ascii("vref"), from_ascii(N_("Standard+Textual Page")), from_ascii(N_("Ref+Text: "))}, + { from_ascii("prettyref"), from_ascii(N_("PrettyRef")), from_ascii(N_("FormatRef: "))}, + { from_ascii(""), from_ascii(""), from_ascii("") } +}; + + +} // namespace lyx diff --git a/src/mathed/InsetMathRoot.C b/src/mathed/InsetMathRoot.C deleted file mode 100644 index 0d81239115..0000000000 --- a/src/mathed/InsetMathRoot.C +++ /dev/null @@ -1,123 +0,0 @@ -/** - * \file InsetMathRoot.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Alejandro Aguilar Sierra - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathRoot.h" -#include "MathData.h" -#include "MathStream.h" -#include "cursor.h" -#include "LColor.h" - -#include "frontends/Painter.h" - - -namespace lyx { - -using std::max; -using std::auto_ptr; - - - -InsetMathRoot::InsetMathRoot() - : InsetMathNest(2) -{} - - -auto_ptr InsetMathRoot::doClone() const -{ - return auto_ptr(new InsetMathRoot(*this)); -} - - -bool InsetMathRoot::metrics(MetricsInfo & mi, Dimension & dim) const -{ - InsetMathNest::metrics(mi); - dim.asc = max(cell(0).ascent() + 5, cell(1).ascent()) + 2; - dim.des = max(cell(0).descent() - 5, cell(1).descent()) + 2; - dim.wid = cell(0).width() + cell(1).width() + 10; - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathRoot::draw(PainterInfo & pi, int x, int y) const -{ - int const w = cell(0).width(); - // the "exponent" - cell(0).draw(pi, x, y - 5 - cell(0).descent()); - // the "base" - cell(1).draw(pi, x + w + 8, y); - int const a = dim_.ascent(); - int const d = dim_.descent(); - int xp[5]; - int yp[5]; - xp[0] = x + dim_.width(); yp[0] = y - a + 1; - xp[1] = x + w + 4; yp[1] = y - a + 1; - xp[2] = x + w; yp[2] = y + d; - xp[3] = x + w - 2; yp[3] = y + (d - a)/2 + 2; - xp[4] = x + w - 5; yp[4] = y + (d - a)/2 + 4; - pi.pain.lines(xp, yp, 5, LColor::math); - drawMarkers(pi, x, y); -} - - -void InsetMathRoot::write(WriteStream & os) const -{ - os << "\\sqrt[" << cell(0) << "]{" << cell(1) << '}'; -} - - -void InsetMathRoot::normalize(NormalStream & os) const -{ - os << "[root " << cell(0) << ' ' << cell(1) << ']'; -} - - -bool InsetMathRoot::idxUpDown(LCursor & cur, bool up) const -{ - LCursor::idx_type const target = up ? 0 : 1; - if (cur.idx() == target) - return false; - cur.idx() = target; - cur.pos() = up ? cur.lastpos() : 0; - return true; -} - - -void InsetMathRoot::maple(MapleStream & os) const -{ - os << '(' << cell(1) << ")^(1/(" << cell(0) <<"))"; -} - - -void InsetMathRoot::mathematica(MathematicaStream & os) const -{ - os << '(' << cell(1) << ")^(1/(" << cell(0) <<"))"; -} - - -void InsetMathRoot::octave(OctaveStream & os) const -{ - os << '(' << cell(1) << ")^(1/(" << cell(0) <<"))"; -} - - -void InsetMathRoot::mathmlize(MathStream & os) const -{ - os << MTag("mroot") << cell(1) << cell(0) << ETag("mroot"); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathRoot.cpp b/src/mathed/InsetMathRoot.cpp new file mode 100644 index 0000000000..0d81239115 --- /dev/null +++ b/src/mathed/InsetMathRoot.cpp @@ -0,0 +1,123 @@ +/** + * \file InsetMathRoot.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Alejandro Aguilar Sierra + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathRoot.h" +#include "MathData.h" +#include "MathStream.h" +#include "cursor.h" +#include "LColor.h" + +#include "frontends/Painter.h" + + +namespace lyx { + +using std::max; +using std::auto_ptr; + + + +InsetMathRoot::InsetMathRoot() + : InsetMathNest(2) +{} + + +auto_ptr InsetMathRoot::doClone() const +{ + return auto_ptr(new InsetMathRoot(*this)); +} + + +bool InsetMathRoot::metrics(MetricsInfo & mi, Dimension & dim) const +{ + InsetMathNest::metrics(mi); + dim.asc = max(cell(0).ascent() + 5, cell(1).ascent()) + 2; + dim.des = max(cell(0).descent() - 5, cell(1).descent()) + 2; + dim.wid = cell(0).width() + cell(1).width() + 10; + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathRoot::draw(PainterInfo & pi, int x, int y) const +{ + int const w = cell(0).width(); + // the "exponent" + cell(0).draw(pi, x, y - 5 - cell(0).descent()); + // the "base" + cell(1).draw(pi, x + w + 8, y); + int const a = dim_.ascent(); + int const d = dim_.descent(); + int xp[5]; + int yp[5]; + xp[0] = x + dim_.width(); yp[0] = y - a + 1; + xp[1] = x + w + 4; yp[1] = y - a + 1; + xp[2] = x + w; yp[2] = y + d; + xp[3] = x + w - 2; yp[3] = y + (d - a)/2 + 2; + xp[4] = x + w - 5; yp[4] = y + (d - a)/2 + 4; + pi.pain.lines(xp, yp, 5, LColor::math); + drawMarkers(pi, x, y); +} + + +void InsetMathRoot::write(WriteStream & os) const +{ + os << "\\sqrt[" << cell(0) << "]{" << cell(1) << '}'; +} + + +void InsetMathRoot::normalize(NormalStream & os) const +{ + os << "[root " << cell(0) << ' ' << cell(1) << ']'; +} + + +bool InsetMathRoot::idxUpDown(LCursor & cur, bool up) const +{ + LCursor::idx_type const target = up ? 0 : 1; + if (cur.idx() == target) + return false; + cur.idx() = target; + cur.pos() = up ? cur.lastpos() : 0; + return true; +} + + +void InsetMathRoot::maple(MapleStream & os) const +{ + os << '(' << cell(1) << ")^(1/(" << cell(0) <<"))"; +} + + +void InsetMathRoot::mathematica(MathematicaStream & os) const +{ + os << '(' << cell(1) << ")^(1/(" << cell(0) <<"))"; +} + + +void InsetMathRoot::octave(OctaveStream & os) const +{ + os << '(' << cell(1) << ")^(1/(" << cell(0) <<"))"; +} + + +void InsetMathRoot::mathmlize(MathStream & os) const +{ + os << MTag("mroot") << cell(1) << cell(0) << ETag("mroot"); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathScript.C b/src/mathed/InsetMathScript.C deleted file mode 100644 index 3080b60ce1..0000000000 --- a/src/mathed/InsetMathScript.C +++ /dev/null @@ -1,715 +0,0 @@ -/** - * \file InsetMathScript.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathScript.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathSupport.h" -#include "InsetMathSymbol.h" -#include "InsetMathFont.h" -#include "dispatchresult.h" -#include "cursor.h" -#include "debug.h" -#include "funcrequest.h" -#include "undo.h" - -#include - - -namespace lyx { - -using std::string; -using std::max; -using std::auto_ptr; -using std::endl; - - - -InsetMathScript::InsetMathScript() - : InsetMathNest(1), cell_1_is_up_(false), limits_(0) -{} - - -InsetMathScript::InsetMathScript(bool up) - : InsetMathNest(2), cell_1_is_up_(up), limits_(0) -{} - - -InsetMathScript::InsetMathScript(MathAtom const & at, bool up) - : InsetMathNest(2), cell_1_is_up_(up), limits_(0) -{ - BOOST_ASSERT(nargs() >= 1); - cell(0).push_back(at); -} - - -auto_ptr InsetMathScript::doClone() const -{ - return auto_ptr(new InsetMathScript(*this)); -} - - -InsetMathScript const * InsetMathScript::asScriptInset() const -{ - return this; -} - - -InsetMathScript * InsetMathScript::asScriptInset() -{ - return this; -} - - -bool InsetMathScript::idxFirst(LCursor & cur) const -{ - cur.idx() = 0; - cur.pos() = 0; - return true; -} - - -bool InsetMathScript::idxLast(LCursor & cur) const -{ - cur.idx() = 0; - cur.pos() = nuc().size(); - return true; -} - - -MathArray const & InsetMathScript::down() const -{ - if (nargs() == 3) - return cell(2); - BOOST_ASSERT(nargs() > 1); - return cell(1); -} - - -MathArray & InsetMathScript::down() -{ - if (nargs() == 3) - return cell(2); - BOOST_ASSERT(nargs() > 1); - return cell(1); -} - - -MathArray const & InsetMathScript::up() const -{ - BOOST_ASSERT(nargs() > 1); - return cell(1); -} - - -MathArray & InsetMathScript::up() -{ - BOOST_ASSERT(nargs() > 1); - return cell(1); -} - - -void InsetMathScript::ensure(bool up) -{ - if (nargs() == 1) { - // just nucleus so far - cells_.push_back(MathArray()); - cell_1_is_up_ = up; - } else if (nargs() == 2 && !has(up)) { - if (up) { - cells_.push_back(cell(1)); - cell(1).clear(); - } else { - cells_.push_back(MathArray()); - } - } -} - - -MathArray const & InsetMathScript::nuc() const -{ - return cell(0); -} - - -MathArray & InsetMathScript::nuc() -{ - return cell(0); -} - - -namespace { - -bool isAlphaSymbol(MathAtom const & at) -{ - if (at->asCharInset() || - (at->asSymbolInset() && - at->asSymbolInset()->isOrdAlpha())) - return true; - - if (at->asFontInset()) { - MathArray const & ar = at->asFontInset()->cell(0); - for (size_t i = 0; i < ar.size(); ++i) { - if (!(ar[i]->asCharInset() || - (ar[i]->asSymbolInset() && - ar[i]->asSymbolInset()->isOrdAlpha()))) - return false; - } - return true; - } - return false; -} - -} // namespace anon - - -int InsetMathScript::dy01(int asc, int des, int what) const -{ - int dasc = 0; - int slevel = 0; - bool isCharBox = nuc().size() ? isAlphaSymbol(nuc().back()) : false; - if (hasDown()) { - dasc = down().ascent(); - slevel = nuc().slevel(); - int ascdrop = dasc - slevel; - int desdrop = isCharBox ? 0 : des + nuc().sshift(); - int mindes = nuc().mindes(); - des = max(desdrop, ascdrop); - des = max(mindes, des); - } - if (hasUp()) { - int minasc = nuc().minasc(); - int ascdrop = isCharBox ? 0 : asc - up().mindes(); - int udes = up().descent(); - asc = udes + nuc().sshift(); - asc = max(ascdrop, asc); - asc = max(minasc, asc); - if (hasDown()) { - int del = asc - udes - dasc; - if (del + des <= 2) { - int newdes = 2 - del; - del = slevel - asc + udes; - if (del > 0) { - asc += del; - newdes -= del; - } - des = max(des, newdes); - } - } - } - return what ? asc : des; -} - - -int InsetMathScript::dy0() const -{ - int nd = ndes(); - if (!hasDown()) - return nd; - int des = down().ascent(); - if (hasLimits()) - des += nd + 2; - else { - int na = nasc(); - des = dy01(na, nd, 0); - } - return des; -} - - -int InsetMathScript::dy1() const -{ - int na = nasc(); - if (!hasUp()) - return na; - int asc = up().descent(); - if (hasLimits()) - asc += na + 2; - else { - int nd = ndes(); - asc = dy01(na, nd, 1); - } - asc = max(asc, 5); - return asc; -} - - -int InsetMathScript::dx0() const -{ - BOOST_ASSERT(hasDown()); - return hasLimits() ? (dim_.wid - down().width()) / 2 : nwid(); -} - - -int InsetMathScript::dx1() const -{ - BOOST_ASSERT(hasUp()); - return hasLimits() ? (dim_.wid - up().width()) / 2 : nwid() + nker(); -} - - -int InsetMathScript::dxx() const -{ - return hasLimits() ? (dim_.wid - nwid()) / 2 : 0; -} - - -int InsetMathScript::nwid() const -{ - return nuc().size() ? nuc().width() : 2; -} - - -int InsetMathScript::nasc() const -{ - return nuc().size() ? nuc().ascent() : 5; -} - - -int InsetMathScript::ndes() const -{ - return nuc().size() ? nuc().descent() : 0; -} - - -int InsetMathScript::nker() const -{ - if (nuc().size()) { - int kerning = nuc().kerning(); - return kerning > 0 ? kerning : 0; - } - return 0; -} - - -bool InsetMathScript::metrics(MetricsInfo & mi, Dimension & dim) const -{ - cell(0).metrics(mi); - ScriptChanger dummy(mi.base); - if (nargs() > 1) - cell(1).metrics(mi); - if (nargs() > 2) - cell(2).metrics(mi); - dim.wid = 0; - if (hasLimits()) { - dim.wid = nwid(); - if (hasUp()) - dim.wid = max(dim.wid, up().width()); - if (hasDown()) - dim.wid = max(dim.wid, down().width()); - } else { - if (hasUp()) - dim.wid = max(dim.wid, nker() + up().width()); - if (hasDown()) - dim.wid = max(dim.wid, down().width()); - dim.wid += nwid(); - } - int na = nasc(); - if (hasUp()) { - int asc = dy1() + up().ascent(); - dim.asc = max(na, asc); - } else - dim.asc = na; - int nd = ndes(); - if (hasDown()) { - int des = dy0() + down().descent(); - dim.des = max(nd, des); - } else - dim.des = nd; - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathScript::draw(PainterInfo & pi, int x, int y) const -{ - if (nuc().size()) - nuc().draw(pi, x + dxx(), y); - else { - nuc().setXY(*pi.base.bv, x + dxx(), y); - if (editing(pi.base.bv)) - pi.draw(x + dxx(), y, char_type('.')); - } - ScriptChanger dummy(pi.base); - if (hasUp()) - up().draw(pi, x + dx1(), y - dy1()); - if (hasDown()) - down().draw(pi, x + dx0(), y + dy0()); - drawMarkers(pi, x, y); -} - - -void InsetMathScript::metricsT(TextMetricsInfo const & mi, Dimension & dim) const -{ - if (hasUp()) - up().metricsT(mi, dim); - if (hasDown()) - down().metricsT(mi, dim); - nuc().metricsT(mi, dim); -} - - -void InsetMathScript::drawT(TextPainter & pain, int x, int y) const -{ - if (nuc().size()) - nuc().drawT(pain, x + dxx(), y); - if (hasUp()) - up().drawT(pain, x + dx1(), y - dy1()); - if (hasDown()) - down().drawT(pain, x + dx0(), y + dy0()); -} - - - -bool InsetMathScript::hasLimits() const -{ - // obvious cases - if (limits_ == 1) - return true; - if (limits_ == -1) - return false; - - // we can only display limits if the nucleus wants some - if (!nuc().size()) - return false; - if (!nuc().back()->isScriptable()) - return false; - - if (nuc().back()->asSymbolInset()) { - // \intop is an alias for \int\limits, \ointop == \oint\limits - if (nuc().back()->asSymbolInset()->name().find(from_ascii("intop")) != string::npos) - return true; - // per default \int has limits beside the \int even in displayed formulas - if (nuc().back()->asSymbolInset()->name().find(from_ascii("int")) != string::npos) - return false; - } - - // assume "real" limits for everything else - return true; -} - - -void InsetMathScript::removeScript(bool up) -{ - if (nargs() == 2) { - if (up == cell_1_is_up_) - cells_.pop_back(); - } else if (nargs() == 3) { - if (up == true) { - swap(cells_[1], cells_[2]); - cell_1_is_up_ = false; - } else { - cell_1_is_up_ = true; - } - cells_.pop_back(); - } -} - - -bool InsetMathScript::has(bool up) const -{ - return idxOfScript(up); -} - - -bool InsetMathScript::hasUp() const -{ - //lyxerr << "1up: " << bool(cell_1_is_up_) << endl; - //lyxerr << "hasUp: " << bool(idxOfScript(true)) << endl; - return idxOfScript(true); -} - - -bool InsetMathScript::hasDown() const -{ - //lyxerr << "1up: " << bool(cell_1_is_up_) << endl; - //lyxerr << "hasDown: " << bool(idxOfScript(false)) << endl; - return idxOfScript(false); -} - - -InsetBase::idx_type InsetMathScript::idxOfScript(bool up) const -{ - if (nargs() == 1) - return 0; - if (nargs() == 2) - return (cell_1_is_up_ == up) ? 1 : 0; - if (nargs() == 3) - return up ? 1 : 2; - BOOST_ASSERT(false); - // Silence compiler - return 0; -} - - -bool InsetMathScript::idxRight(LCursor &) const -{ - return false; -} - - -bool InsetMathScript::idxLeft(LCursor &) const -{ - return false; -} - - -bool InsetMathScript::idxUpDown(LCursor & cur, bool up) const -{ - // in nucleus? - if (cur.idx() == 0) { - // don't go up/down if there is no cell in this direction - if (!has(up)) - return false; - // go up/down only if in the last position - // or in the first position of something with displayed limits - if (cur.pos() == cur.lastpos() || (cur.pos() == 0 && hasLimits())) { - cur.idx() = idxOfScript(up); - cur.pos() = 0; - return true; - } - return false; - } - - // Are we 'up'? - if (has(up) && cur.idx() == idxOfScript(true)) { - // can't go further up - if (up) - return false; - // otherwise go to last position in the nucleus - cur.idx() = 0; - cur.pos() = cur.lastpos(); - return true; - } - - // Are we 'down'? - if (has(up) && cur.idx() == idxOfScript(false)) { - // can't go further down - if (!up) - return false; - // otherwise go to last position in the nucleus - cur.idx() = 0; - cur.pos() = cur.lastpos(); - return true; - } - - return false; -} - - -void InsetMathScript::write(WriteStream & os) const -{ - if (nuc().size()) { - os << nuc(); - //if (nuc().back()->takesLimits()) { - if (limits_ == -1) - os << "\\nolimits "; - if (limits_ == 1) - os << "\\limits "; - //} - } else { - if (os.firstitem()) - LYXERR(Debug::MATHED) << "suppressing {} when writing" - << endl; - else - os << "{}"; - } - - if (hasDown() /*&& down().size()*/) - os << "_{" << down() << '}'; - - if (hasUp() /*&& up().size()*/) - os << "^{" << up() << '}'; - - if (lock_ && !os.latex()) - os << "\\lyxlock "; -} - - -void InsetMathScript::normalize(NormalStream & os) const -{ - bool d = hasDown() && down().size(); - bool u = hasUp() && up().size(); - - if (u && d) - os << "[subsup "; - else if (u) - os << "[sup "; - else if (d) - os << "[sub "; - - if (nuc().size()) - os << nuc() << ' '; - else - os << "[par]"; - - if (u && d) - os << down() << ' ' << up() << ']'; - else if (d) - os << down() << ']'; - else if (u) - os << up() << ']'; -} - - -void InsetMathScript::maple(MapleStream & os) const -{ - if (nuc().size()) - os << nuc(); - if (hasDown() && down().size()) - os << '[' << down() << ']'; - if (hasUp() && up().size()) - os << "^(" << up() << ')'; -} - - -void InsetMathScript::mathematica(MathematicaStream & os) const -{ - bool d = hasDown() && down().size(); - bool u = hasUp() && up().size(); - - if (nuc().size()) { - if (d) - os << "Subscript[" << nuc(); - else - os << nuc(); - } - - if (u) - os << "^(" << up() << ')'; - - if (nuc().size()) { - if (d) - os << ',' << down() << ']'; - } -} - - -void InsetMathScript::mathmlize(MathStream & os) const -{ - bool d = hasDown() && down().size(); - bool u = hasUp() && up().size(); - - if (u && d) - os << MTag("msubsup"); - else if (u) - os << MTag("msup"); - else if (d) - os << MTag("msub"); - - if (nuc().size()) - os << nuc(); - else - os << ""; - - if (u && d) - os << down() << up() << ETag("msubsup"); - else if (u) - os << up() << ETag("msup"); - else if (d) - os << down() << ETag("msub"); -} - - -void InsetMathScript::octave(OctaveStream & os) const -{ - if (nuc().size()) - os << nuc(); - if (hasDown() && down().size()) - os << '[' << down() << ']'; - if (hasUp() && up().size()) - os << "^(" << up() << ')'; -} - - -void InsetMathScript::infoize(odocstream & os) const -{ - os << "Scripts"; -} - - -void InsetMathScript::infoize2(odocstream & os) const -{ - if (limits_) - os << (limits_ == 1 ? ", Displayed limits" : ", Inlined limits"); -} - - -bool InsetMathScript::notifyCursorLeaves(LCursor & cur) -{ - InsetMathNest::notifyCursorLeaves(cur); - - //lyxerr << "InsetMathScript::notifyCursorLeaves: 1 " << cur << endl; - - // remove empty scripts if possible - if (nargs() > 2) { - // Case of two scripts. In this case, 1 = super, 2 = sub - if (cur.idx() == 2 && cell(2).empty()) { - // must be a subscript... - recordUndoInset(cur); - removeScript(false); - return true; - } else if (cur.idx() == 1 && cell(1).empty()) { - // must be a superscript... - recordUndoInset(cur); - removeScript(true); - return true; - } - } else if (nargs() > 1 && cur.idx() == 1 && cell(1).empty()) { - // could be either subscript or super script - recordUndoInset(cur); - removeScript(cell_1_is_up_); - // Let the script inset commit suicide. This is - // modelled on LCursor.pullArg(), but tries not to - // invoke notifyCursorLeaves again and does not touch - // cur (since the top slice will be deleted - // afterwards)) - MathArray ar = cell(0); - LCursor tmpcur = cur; - tmpcur.pop(); - tmpcur.cell().erase(tmpcur.pos()); - tmpcur.cell().insert(tmpcur.pos(), ar); - return true; - } - - //lyxerr << "InsetMathScript::notifyCursorLeaves: 2 " << cur << endl; - return false; -} - - -void InsetMathScript::doDispatch(LCursor & cur, FuncRequest & cmd) -{ - //lyxerr << "InsetMathScript: request: " << cmd << std::endl; - - if (cmd.action == LFUN_MATH_LIMITS) { - if (!cmd.argument().empty()) { - if (cmd.argument() == "limits") - limits_ = 1; - else if (cmd.argument() == "nolimits") - limits_ = -1; - else - limits_ = 0; - } else if (limits_ == 0) - limits_ = hasLimits() ? -1 : 1; - else - limits_ = 0; - return; - } - - InsetMathNest::doDispatch(cur, cmd); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathScript.cpp b/src/mathed/InsetMathScript.cpp new file mode 100644 index 0000000000..3080b60ce1 --- /dev/null +++ b/src/mathed/InsetMathScript.cpp @@ -0,0 +1,715 @@ +/** + * \file InsetMathScript.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathScript.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathSupport.h" +#include "InsetMathSymbol.h" +#include "InsetMathFont.h" +#include "dispatchresult.h" +#include "cursor.h" +#include "debug.h" +#include "funcrequest.h" +#include "undo.h" + +#include + + +namespace lyx { + +using std::string; +using std::max; +using std::auto_ptr; +using std::endl; + + + +InsetMathScript::InsetMathScript() + : InsetMathNest(1), cell_1_is_up_(false), limits_(0) +{} + + +InsetMathScript::InsetMathScript(bool up) + : InsetMathNest(2), cell_1_is_up_(up), limits_(0) +{} + + +InsetMathScript::InsetMathScript(MathAtom const & at, bool up) + : InsetMathNest(2), cell_1_is_up_(up), limits_(0) +{ + BOOST_ASSERT(nargs() >= 1); + cell(0).push_back(at); +} + + +auto_ptr InsetMathScript::doClone() const +{ + return auto_ptr(new InsetMathScript(*this)); +} + + +InsetMathScript const * InsetMathScript::asScriptInset() const +{ + return this; +} + + +InsetMathScript * InsetMathScript::asScriptInset() +{ + return this; +} + + +bool InsetMathScript::idxFirst(LCursor & cur) const +{ + cur.idx() = 0; + cur.pos() = 0; + return true; +} + + +bool InsetMathScript::idxLast(LCursor & cur) const +{ + cur.idx() = 0; + cur.pos() = nuc().size(); + return true; +} + + +MathArray const & InsetMathScript::down() const +{ + if (nargs() == 3) + return cell(2); + BOOST_ASSERT(nargs() > 1); + return cell(1); +} + + +MathArray & InsetMathScript::down() +{ + if (nargs() == 3) + return cell(2); + BOOST_ASSERT(nargs() > 1); + return cell(1); +} + + +MathArray const & InsetMathScript::up() const +{ + BOOST_ASSERT(nargs() > 1); + return cell(1); +} + + +MathArray & InsetMathScript::up() +{ + BOOST_ASSERT(nargs() > 1); + return cell(1); +} + + +void InsetMathScript::ensure(bool up) +{ + if (nargs() == 1) { + // just nucleus so far + cells_.push_back(MathArray()); + cell_1_is_up_ = up; + } else if (nargs() == 2 && !has(up)) { + if (up) { + cells_.push_back(cell(1)); + cell(1).clear(); + } else { + cells_.push_back(MathArray()); + } + } +} + + +MathArray const & InsetMathScript::nuc() const +{ + return cell(0); +} + + +MathArray & InsetMathScript::nuc() +{ + return cell(0); +} + + +namespace { + +bool isAlphaSymbol(MathAtom const & at) +{ + if (at->asCharInset() || + (at->asSymbolInset() && + at->asSymbolInset()->isOrdAlpha())) + return true; + + if (at->asFontInset()) { + MathArray const & ar = at->asFontInset()->cell(0); + for (size_t i = 0; i < ar.size(); ++i) { + if (!(ar[i]->asCharInset() || + (ar[i]->asSymbolInset() && + ar[i]->asSymbolInset()->isOrdAlpha()))) + return false; + } + return true; + } + return false; +} + +} // namespace anon + + +int InsetMathScript::dy01(int asc, int des, int what) const +{ + int dasc = 0; + int slevel = 0; + bool isCharBox = nuc().size() ? isAlphaSymbol(nuc().back()) : false; + if (hasDown()) { + dasc = down().ascent(); + slevel = nuc().slevel(); + int ascdrop = dasc - slevel; + int desdrop = isCharBox ? 0 : des + nuc().sshift(); + int mindes = nuc().mindes(); + des = max(desdrop, ascdrop); + des = max(mindes, des); + } + if (hasUp()) { + int minasc = nuc().minasc(); + int ascdrop = isCharBox ? 0 : asc - up().mindes(); + int udes = up().descent(); + asc = udes + nuc().sshift(); + asc = max(ascdrop, asc); + asc = max(minasc, asc); + if (hasDown()) { + int del = asc - udes - dasc; + if (del + des <= 2) { + int newdes = 2 - del; + del = slevel - asc + udes; + if (del > 0) { + asc += del; + newdes -= del; + } + des = max(des, newdes); + } + } + } + return what ? asc : des; +} + + +int InsetMathScript::dy0() const +{ + int nd = ndes(); + if (!hasDown()) + return nd; + int des = down().ascent(); + if (hasLimits()) + des += nd + 2; + else { + int na = nasc(); + des = dy01(na, nd, 0); + } + return des; +} + + +int InsetMathScript::dy1() const +{ + int na = nasc(); + if (!hasUp()) + return na; + int asc = up().descent(); + if (hasLimits()) + asc += na + 2; + else { + int nd = ndes(); + asc = dy01(na, nd, 1); + } + asc = max(asc, 5); + return asc; +} + + +int InsetMathScript::dx0() const +{ + BOOST_ASSERT(hasDown()); + return hasLimits() ? (dim_.wid - down().width()) / 2 : nwid(); +} + + +int InsetMathScript::dx1() const +{ + BOOST_ASSERT(hasUp()); + return hasLimits() ? (dim_.wid - up().width()) / 2 : nwid() + nker(); +} + + +int InsetMathScript::dxx() const +{ + return hasLimits() ? (dim_.wid - nwid()) / 2 : 0; +} + + +int InsetMathScript::nwid() const +{ + return nuc().size() ? nuc().width() : 2; +} + + +int InsetMathScript::nasc() const +{ + return nuc().size() ? nuc().ascent() : 5; +} + + +int InsetMathScript::ndes() const +{ + return nuc().size() ? nuc().descent() : 0; +} + + +int InsetMathScript::nker() const +{ + if (nuc().size()) { + int kerning = nuc().kerning(); + return kerning > 0 ? kerning : 0; + } + return 0; +} + + +bool InsetMathScript::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(0).metrics(mi); + ScriptChanger dummy(mi.base); + if (nargs() > 1) + cell(1).metrics(mi); + if (nargs() > 2) + cell(2).metrics(mi); + dim.wid = 0; + if (hasLimits()) { + dim.wid = nwid(); + if (hasUp()) + dim.wid = max(dim.wid, up().width()); + if (hasDown()) + dim.wid = max(dim.wid, down().width()); + } else { + if (hasUp()) + dim.wid = max(dim.wid, nker() + up().width()); + if (hasDown()) + dim.wid = max(dim.wid, down().width()); + dim.wid += nwid(); + } + int na = nasc(); + if (hasUp()) { + int asc = dy1() + up().ascent(); + dim.asc = max(na, asc); + } else + dim.asc = na; + int nd = ndes(); + if (hasDown()) { + int des = dy0() + down().descent(); + dim.des = max(nd, des); + } else + dim.des = nd; + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathScript::draw(PainterInfo & pi, int x, int y) const +{ + if (nuc().size()) + nuc().draw(pi, x + dxx(), y); + else { + nuc().setXY(*pi.base.bv, x + dxx(), y); + if (editing(pi.base.bv)) + pi.draw(x + dxx(), y, char_type('.')); + } + ScriptChanger dummy(pi.base); + if (hasUp()) + up().draw(pi, x + dx1(), y - dy1()); + if (hasDown()) + down().draw(pi, x + dx0(), y + dy0()); + drawMarkers(pi, x, y); +} + + +void InsetMathScript::metricsT(TextMetricsInfo const & mi, Dimension & dim) const +{ + if (hasUp()) + up().metricsT(mi, dim); + if (hasDown()) + down().metricsT(mi, dim); + nuc().metricsT(mi, dim); +} + + +void InsetMathScript::drawT(TextPainter & pain, int x, int y) const +{ + if (nuc().size()) + nuc().drawT(pain, x + dxx(), y); + if (hasUp()) + up().drawT(pain, x + dx1(), y - dy1()); + if (hasDown()) + down().drawT(pain, x + dx0(), y + dy0()); +} + + + +bool InsetMathScript::hasLimits() const +{ + // obvious cases + if (limits_ == 1) + return true; + if (limits_ == -1) + return false; + + // we can only display limits if the nucleus wants some + if (!nuc().size()) + return false; + if (!nuc().back()->isScriptable()) + return false; + + if (nuc().back()->asSymbolInset()) { + // \intop is an alias for \int\limits, \ointop == \oint\limits + if (nuc().back()->asSymbolInset()->name().find(from_ascii("intop")) != string::npos) + return true; + // per default \int has limits beside the \int even in displayed formulas + if (nuc().back()->asSymbolInset()->name().find(from_ascii("int")) != string::npos) + return false; + } + + // assume "real" limits for everything else + return true; +} + + +void InsetMathScript::removeScript(bool up) +{ + if (nargs() == 2) { + if (up == cell_1_is_up_) + cells_.pop_back(); + } else if (nargs() == 3) { + if (up == true) { + swap(cells_[1], cells_[2]); + cell_1_is_up_ = false; + } else { + cell_1_is_up_ = true; + } + cells_.pop_back(); + } +} + + +bool InsetMathScript::has(bool up) const +{ + return idxOfScript(up); +} + + +bool InsetMathScript::hasUp() const +{ + //lyxerr << "1up: " << bool(cell_1_is_up_) << endl; + //lyxerr << "hasUp: " << bool(idxOfScript(true)) << endl; + return idxOfScript(true); +} + + +bool InsetMathScript::hasDown() const +{ + //lyxerr << "1up: " << bool(cell_1_is_up_) << endl; + //lyxerr << "hasDown: " << bool(idxOfScript(false)) << endl; + return idxOfScript(false); +} + + +InsetBase::idx_type InsetMathScript::idxOfScript(bool up) const +{ + if (nargs() == 1) + return 0; + if (nargs() == 2) + return (cell_1_is_up_ == up) ? 1 : 0; + if (nargs() == 3) + return up ? 1 : 2; + BOOST_ASSERT(false); + // Silence compiler + return 0; +} + + +bool InsetMathScript::idxRight(LCursor &) const +{ + return false; +} + + +bool InsetMathScript::idxLeft(LCursor &) const +{ + return false; +} + + +bool InsetMathScript::idxUpDown(LCursor & cur, bool up) const +{ + // in nucleus? + if (cur.idx() == 0) { + // don't go up/down if there is no cell in this direction + if (!has(up)) + return false; + // go up/down only if in the last position + // or in the first position of something with displayed limits + if (cur.pos() == cur.lastpos() || (cur.pos() == 0 && hasLimits())) { + cur.idx() = idxOfScript(up); + cur.pos() = 0; + return true; + } + return false; + } + + // Are we 'up'? + if (has(up) && cur.idx() == idxOfScript(true)) { + // can't go further up + if (up) + return false; + // otherwise go to last position in the nucleus + cur.idx() = 0; + cur.pos() = cur.lastpos(); + return true; + } + + // Are we 'down'? + if (has(up) && cur.idx() == idxOfScript(false)) { + // can't go further down + if (!up) + return false; + // otherwise go to last position in the nucleus + cur.idx() = 0; + cur.pos() = cur.lastpos(); + return true; + } + + return false; +} + + +void InsetMathScript::write(WriteStream & os) const +{ + if (nuc().size()) { + os << nuc(); + //if (nuc().back()->takesLimits()) { + if (limits_ == -1) + os << "\\nolimits "; + if (limits_ == 1) + os << "\\limits "; + //} + } else { + if (os.firstitem()) + LYXERR(Debug::MATHED) << "suppressing {} when writing" + << endl; + else + os << "{}"; + } + + if (hasDown() /*&& down().size()*/) + os << "_{" << down() << '}'; + + if (hasUp() /*&& up().size()*/) + os << "^{" << up() << '}'; + + if (lock_ && !os.latex()) + os << "\\lyxlock "; +} + + +void InsetMathScript::normalize(NormalStream & os) const +{ + bool d = hasDown() && down().size(); + bool u = hasUp() && up().size(); + + if (u && d) + os << "[subsup "; + else if (u) + os << "[sup "; + else if (d) + os << "[sub "; + + if (nuc().size()) + os << nuc() << ' '; + else + os << "[par]"; + + if (u && d) + os << down() << ' ' << up() << ']'; + else if (d) + os << down() << ']'; + else if (u) + os << up() << ']'; +} + + +void InsetMathScript::maple(MapleStream & os) const +{ + if (nuc().size()) + os << nuc(); + if (hasDown() && down().size()) + os << '[' << down() << ']'; + if (hasUp() && up().size()) + os << "^(" << up() << ')'; +} + + +void InsetMathScript::mathematica(MathematicaStream & os) const +{ + bool d = hasDown() && down().size(); + bool u = hasUp() && up().size(); + + if (nuc().size()) { + if (d) + os << "Subscript[" << nuc(); + else + os << nuc(); + } + + if (u) + os << "^(" << up() << ')'; + + if (nuc().size()) { + if (d) + os << ',' << down() << ']'; + } +} + + +void InsetMathScript::mathmlize(MathStream & os) const +{ + bool d = hasDown() && down().size(); + bool u = hasUp() && up().size(); + + if (u && d) + os << MTag("msubsup"); + else if (u) + os << MTag("msup"); + else if (d) + os << MTag("msub"); + + if (nuc().size()) + os << nuc(); + else + os << ""; + + if (u && d) + os << down() << up() << ETag("msubsup"); + else if (u) + os << up() << ETag("msup"); + else if (d) + os << down() << ETag("msub"); +} + + +void InsetMathScript::octave(OctaveStream & os) const +{ + if (nuc().size()) + os << nuc(); + if (hasDown() && down().size()) + os << '[' << down() << ']'; + if (hasUp() && up().size()) + os << "^(" << up() << ')'; +} + + +void InsetMathScript::infoize(odocstream & os) const +{ + os << "Scripts"; +} + + +void InsetMathScript::infoize2(odocstream & os) const +{ + if (limits_) + os << (limits_ == 1 ? ", Displayed limits" : ", Inlined limits"); +} + + +bool InsetMathScript::notifyCursorLeaves(LCursor & cur) +{ + InsetMathNest::notifyCursorLeaves(cur); + + //lyxerr << "InsetMathScript::notifyCursorLeaves: 1 " << cur << endl; + + // remove empty scripts if possible + if (nargs() > 2) { + // Case of two scripts. In this case, 1 = super, 2 = sub + if (cur.idx() == 2 && cell(2).empty()) { + // must be a subscript... + recordUndoInset(cur); + removeScript(false); + return true; + } else if (cur.idx() == 1 && cell(1).empty()) { + // must be a superscript... + recordUndoInset(cur); + removeScript(true); + return true; + } + } else if (nargs() > 1 && cur.idx() == 1 && cell(1).empty()) { + // could be either subscript or super script + recordUndoInset(cur); + removeScript(cell_1_is_up_); + // Let the script inset commit suicide. This is + // modelled on LCursor.pullArg(), but tries not to + // invoke notifyCursorLeaves again and does not touch + // cur (since the top slice will be deleted + // afterwards)) + MathArray ar = cell(0); + LCursor tmpcur = cur; + tmpcur.pop(); + tmpcur.cell().erase(tmpcur.pos()); + tmpcur.cell().insert(tmpcur.pos(), ar); + return true; + } + + //lyxerr << "InsetMathScript::notifyCursorLeaves: 2 " << cur << endl; + return false; +} + + +void InsetMathScript::doDispatch(LCursor & cur, FuncRequest & cmd) +{ + //lyxerr << "InsetMathScript: request: " << cmd << std::endl; + + if (cmd.action == LFUN_MATH_LIMITS) { + if (!cmd.argument().empty()) { + if (cmd.argument() == "limits") + limits_ = 1; + else if (cmd.argument() == "nolimits") + limits_ = -1; + else + limits_ = 0; + } else if (limits_ == 0) + limits_ = hasLimits() ? -1 : 1; + else + limits_ = 0; + return; + } + + InsetMathNest::doDispatch(cur, cmd); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathSize.C b/src/mathed/InsetMathSize.C deleted file mode 100644 index 23eb69812a..0000000000 --- a/src/mathed/InsetMathSize.C +++ /dev/null @@ -1,76 +0,0 @@ -/** - * \file InsetMathSize.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathSize.h" -#include "MathData.h" -#include "MathParser.h" -#include "MathStream.h" - -#include "support/convert.h" -#include "support/std_ostream.h" - - -namespace lyx { - -using std::auto_ptr; - - -InsetMathSize::InsetMathSize(latexkeys const * l) - : InsetMathNest(1), key_(l), style_(Styles(convert(l->extra))) -{} - - -auto_ptr InsetMathSize::doClone() const -{ - return auto_ptr(new InsetMathSize(*this)); -} - - -bool InsetMathSize::metrics(MetricsInfo & mi, Dimension & dim) const -{ - StyleChanger dummy(mi.base, style_); - cell(0).metrics(mi, dim); - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathSize::draw(PainterInfo & pi, int x, int y) const -{ - StyleChanger dummy(pi.base, style_); - cell(0).draw(pi, x + 1, y); - drawMarkers(pi, x, y); -} - - -void InsetMathSize::write(WriteStream & os) const -{ - os << "{\\" << key_->name << ' ' << cell(0) << '}'; -} - - -void InsetMathSize::normalize(NormalStream & os) const -{ - os << '[' << key_->name << ' ' << cell(0) << ']'; -} - - -void InsetMathSize::infoize(odocstream & os) const -{ - os << "Size: " << key_->name; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathSize.cpp b/src/mathed/InsetMathSize.cpp new file mode 100644 index 0000000000..23eb69812a --- /dev/null +++ b/src/mathed/InsetMathSize.cpp @@ -0,0 +1,76 @@ +/** + * \file InsetMathSize.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathSize.h" +#include "MathData.h" +#include "MathParser.h" +#include "MathStream.h" + +#include "support/convert.h" +#include "support/std_ostream.h" + + +namespace lyx { + +using std::auto_ptr; + + +InsetMathSize::InsetMathSize(latexkeys const * l) + : InsetMathNest(1), key_(l), style_(Styles(convert(l->extra))) +{} + + +auto_ptr InsetMathSize::doClone() const +{ + return auto_ptr(new InsetMathSize(*this)); +} + + +bool InsetMathSize::metrics(MetricsInfo & mi, Dimension & dim) const +{ + StyleChanger dummy(mi.base, style_); + cell(0).metrics(mi, dim); + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathSize::draw(PainterInfo & pi, int x, int y) const +{ + StyleChanger dummy(pi.base, style_); + cell(0).draw(pi, x + 1, y); + drawMarkers(pi, x, y); +} + + +void InsetMathSize::write(WriteStream & os) const +{ + os << "{\\" << key_->name << ' ' << cell(0) << '}'; +} + + +void InsetMathSize::normalize(NormalStream & os) const +{ + os << '[' << key_->name << ' ' << cell(0) << ']'; +} + + +void InsetMathSize::infoize(odocstream & os) const +{ + os << "Size: " << key_->name; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathSpace.C b/src/mathed/InsetMathSpace.C deleted file mode 100644 index 8d3df0930b..0000000000 --- a/src/mathed/InsetMathSpace.C +++ /dev/null @@ -1,165 +0,0 @@ -/** - * \file InsetMathSpace.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathSpace.h" -#include "MathData.h" -#include "MathStream.h" - -#include "LaTeXFeatures.h" -#include "LColor.h" - -#include "frontends/Painter.h" - -using std::string; -using std::auto_ptr; - - -namespace lyx { - -char const * latex_mathspace[] = { - "!", "negmedspace", "negthickspace", // negative space - ",", ":", ";", "quad", "qquad", // positive space - "lyxnegspace", "lyxposspace" // LyX special ("unvisible space") -}; - -int const nSpace = sizeof(latex_mathspace)/sizeof(char *); - -namespace { - -int spaceToWidth(int space) -{ - switch (space) { - case 0: return 6; - case 1: return 8; - case 2: return 10; - case 3: return 6; - case 4: return 8; - case 5: return 10; - case 6: return 20; - case 7: return 40; - case 8: return -2; - case 9: return 2; - default: return 6; - } -} - -} // anon namespace - -InsetMathSpace::InsetMathSpace(int sp) - : space_(sp) -{ - dim_.asc = 4; - dim_.des = 0; - dim_.wid = spaceToWidth(space_); -} - - -InsetMathSpace::InsetMathSpace(docstring const & name) - : space_(1) -{ - dim_.asc = 4; - dim_.des = 0; - for (int i = 0; i < nSpace; ++i) - if (latex_mathspace[i] == name) - space_ = i; - dim_.wid = spaceToWidth(space_); -} - - -auto_ptr InsetMathSpace::doClone() const -{ - return auto_ptr(new InsetMathSpace(*this)); -} - - -bool InsetMathSpace::metrics(MetricsInfo &, Dimension & dim) const -{ - dim.wid = width(); - dim.asc = ascent(); - dim.des = descent(); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathSpace::draw(PainterInfo & pi, int x, int y) const -{ - // Sadly, HP-UX CC can't handle that kind of initialization. - // XPoint p[4] = {{++x, y-3}, {x, y}, {x+width-2, y}, {x+width-2, y-3}}; - if (space_ >= nSpace - 2) - return; - - int xp[4]; - int yp[4]; - int w = width(); - - xp[0] = ++x; yp[0] = y - 3; - xp[1] = x; yp[1] = y; - xp[2] = x + w - 2; yp[2] = y; - xp[3] = x + w - 2; yp[3] = y - 3; - - pi.pain.lines(xp, yp, 4, (space_ < 3) ? LColor::latex : LColor::math); -} - - -void InsetMathSpace::incSpace() -{ - space_ = (space_ + 1) % (nSpace - 2); - dim_.wid = spaceToWidth(space_); -} - - -void InsetMathSpace::validate(LaTeXFeatures & features) const -{ - if (space_ >= 0 && space_< nSpace) { - if ((latex_mathspace[space_] == string("negmedspace")) - || (latex_mathspace[space_] == string("negthickspace"))) - features.require("amsmath"); - } -} - - -void InsetMathSpace::maple(MapleStream & os) const -{ - os << ' '; -} - -void InsetMathSpace::mathematica(MathematicaStream & os) const -{ - os << ' '; -} - - -void InsetMathSpace::octave(OctaveStream & os) const -{ - os << ' '; -} - - -void InsetMathSpace::normalize(NormalStream & os) const -{ - os << "[space " << int(space_) << "] "; -} - - -void InsetMathSpace::write(WriteStream & os) const -{ - if (space_ >= 0 && space_ < nSpace) { - os << '\\' << latex_mathspace[space_]; - os.pendingSpace(true); - } -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathSpace.cpp b/src/mathed/InsetMathSpace.cpp new file mode 100644 index 0000000000..8d3df0930b --- /dev/null +++ b/src/mathed/InsetMathSpace.cpp @@ -0,0 +1,165 @@ +/** + * \file InsetMathSpace.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathSpace.h" +#include "MathData.h" +#include "MathStream.h" + +#include "LaTeXFeatures.h" +#include "LColor.h" + +#include "frontends/Painter.h" + +using std::string; +using std::auto_ptr; + + +namespace lyx { + +char const * latex_mathspace[] = { + "!", "negmedspace", "negthickspace", // negative space + ",", ":", ";", "quad", "qquad", // positive space + "lyxnegspace", "lyxposspace" // LyX special ("unvisible space") +}; + +int const nSpace = sizeof(latex_mathspace)/sizeof(char *); + +namespace { + +int spaceToWidth(int space) +{ + switch (space) { + case 0: return 6; + case 1: return 8; + case 2: return 10; + case 3: return 6; + case 4: return 8; + case 5: return 10; + case 6: return 20; + case 7: return 40; + case 8: return -2; + case 9: return 2; + default: return 6; + } +} + +} // anon namespace + +InsetMathSpace::InsetMathSpace(int sp) + : space_(sp) +{ + dim_.asc = 4; + dim_.des = 0; + dim_.wid = spaceToWidth(space_); +} + + +InsetMathSpace::InsetMathSpace(docstring const & name) + : space_(1) +{ + dim_.asc = 4; + dim_.des = 0; + for (int i = 0; i < nSpace; ++i) + if (latex_mathspace[i] == name) + space_ = i; + dim_.wid = spaceToWidth(space_); +} + + +auto_ptr InsetMathSpace::doClone() const +{ + return auto_ptr(new InsetMathSpace(*this)); +} + + +bool InsetMathSpace::metrics(MetricsInfo &, Dimension & dim) const +{ + dim.wid = width(); + dim.asc = ascent(); + dim.des = descent(); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathSpace::draw(PainterInfo & pi, int x, int y) const +{ + // Sadly, HP-UX CC can't handle that kind of initialization. + // XPoint p[4] = {{++x, y-3}, {x, y}, {x+width-2, y}, {x+width-2, y-3}}; + if (space_ >= nSpace - 2) + return; + + int xp[4]; + int yp[4]; + int w = width(); + + xp[0] = ++x; yp[0] = y - 3; + xp[1] = x; yp[1] = y; + xp[2] = x + w - 2; yp[2] = y; + xp[3] = x + w - 2; yp[3] = y - 3; + + pi.pain.lines(xp, yp, 4, (space_ < 3) ? LColor::latex : LColor::math); +} + + +void InsetMathSpace::incSpace() +{ + space_ = (space_ + 1) % (nSpace - 2); + dim_.wid = spaceToWidth(space_); +} + + +void InsetMathSpace::validate(LaTeXFeatures & features) const +{ + if (space_ >= 0 && space_< nSpace) { + if ((latex_mathspace[space_] == string("negmedspace")) + || (latex_mathspace[space_] == string("negthickspace"))) + features.require("amsmath"); + } +} + + +void InsetMathSpace::maple(MapleStream & os) const +{ + os << ' '; +} + +void InsetMathSpace::mathematica(MathematicaStream & os) const +{ + os << ' '; +} + + +void InsetMathSpace::octave(OctaveStream & os) const +{ + os << ' '; +} + + +void InsetMathSpace::normalize(NormalStream & os) const +{ + os << "[space " << int(space_) << "] "; +} + + +void InsetMathSpace::write(WriteStream & os) const +{ + if (space_ >= 0 && space_ < nSpace) { + os << '\\' << latex_mathspace[space_]; + os.pendingSpace(true); + } +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathSplit.C b/src/mathed/InsetMathSplit.C deleted file mode 100644 index a8575ac687..0000000000 --- a/src/mathed/InsetMathSplit.C +++ /dev/null @@ -1,121 +0,0 @@ -/** - * \file InsetMathSplit.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathSplit.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathStream.h" - -#include "funcrequest.h" -#include "FuncStatus.h" -#include "gettext.h" -#include "LaTeXFeatures.h" - -#include "support/lstrings.h" -#include "support/std_ostream.h" - - -namespace lyx { - -using support::bformat; - -using std::string; -using std::auto_ptr; - - -InsetMathSplit::InsetMathSplit(docstring const & name, char valign) - : InsetMathGrid(1, 1, valign, docstring()), name_(name) -{ -} - - -auto_ptr InsetMathSplit::doClone() const -{ - return auto_ptr(new InsetMathSplit(*this)); -} - - -char InsetMathSplit::defaultColAlign(col_type col) -{ - if (name_ == "split") - return 'l'; - if (name_ == "gathered") - return 'c'; - if (name_ == "aligned") - return (col & 1) ? 'l' : 'r'; - if (name_ == "alignedat") - return (col & 1) ? 'l' : 'r'; - return 'l'; -} - - -void InsetMathSplit::draw(PainterInfo & pi, int x, int y) const -{ - InsetMathGrid::draw(pi, x, y); - setPosCache(pi, x, y); -} - - -bool InsetMathSplit::getStatus(LCursor & cur, FuncRequest const & cmd, - FuncStatus & flag) const -{ - switch (cmd.action) { - case LFUN_TABULAR_FEATURE: { - docstring const & s = cmd.argument(); - if (s == "add-vline-left" || s == "add-vline-right") { - flag.message(bformat( - from_utf8(N_("Can't add vertical grid lines in '%1$s'")), name_)); - flag.enabled(false); - return true; - } - return InsetMathGrid::getStatus(cur, cmd, flag); - } - default: - return InsetMathGrid::getStatus(cur, cmd, flag); - } -} - - -void InsetMathSplit::write(WriteStream & ws) const -{ - if (ws.fragile()) - ws << "\\protect"; - ws << "\\begin{" << name_ << '}'; - if (name_ != "split" && valign() != 'c') - ws << '[' << valign() << ']'; - if (name_ == "alignedat") - ws << '{' << static_cast((ncols() + 1)/2) << '}'; - InsetMathGrid::write(ws); - if (ws.fragile()) - ws << "\\protect"; - ws << "\\end{" << name_ << "}\n"; -} - - -void InsetMathSplit::infoize(odocstream & os) const -{ - docstring name = name_; - name[0] = support::uppercase(name[0]); - os << name << ' '; -} - - -void InsetMathSplit::validate(LaTeXFeatures & features) const -{ - if (name_ == "split" || name_ == "gathered" || name_ == "aligned" || - name_ == "alignedat") - features.require("amsmath"); - InsetMathGrid::validate(features); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathSplit.cpp b/src/mathed/InsetMathSplit.cpp new file mode 100644 index 0000000000..a8575ac687 --- /dev/null +++ b/src/mathed/InsetMathSplit.cpp @@ -0,0 +1,121 @@ +/** + * \file InsetMathSplit.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathSplit.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathStream.h" + +#include "funcrequest.h" +#include "FuncStatus.h" +#include "gettext.h" +#include "LaTeXFeatures.h" + +#include "support/lstrings.h" +#include "support/std_ostream.h" + + +namespace lyx { + +using support::bformat; + +using std::string; +using std::auto_ptr; + + +InsetMathSplit::InsetMathSplit(docstring const & name, char valign) + : InsetMathGrid(1, 1, valign, docstring()), name_(name) +{ +} + + +auto_ptr InsetMathSplit::doClone() const +{ + return auto_ptr(new InsetMathSplit(*this)); +} + + +char InsetMathSplit::defaultColAlign(col_type col) +{ + if (name_ == "split") + return 'l'; + if (name_ == "gathered") + return 'c'; + if (name_ == "aligned") + return (col & 1) ? 'l' : 'r'; + if (name_ == "alignedat") + return (col & 1) ? 'l' : 'r'; + return 'l'; +} + + +void InsetMathSplit::draw(PainterInfo & pi, int x, int y) const +{ + InsetMathGrid::draw(pi, x, y); + setPosCache(pi, x, y); +} + + +bool InsetMathSplit::getStatus(LCursor & cur, FuncRequest const & cmd, + FuncStatus & flag) const +{ + switch (cmd.action) { + case LFUN_TABULAR_FEATURE: { + docstring const & s = cmd.argument(); + if (s == "add-vline-left" || s == "add-vline-right") { + flag.message(bformat( + from_utf8(N_("Can't add vertical grid lines in '%1$s'")), name_)); + flag.enabled(false); + return true; + } + return InsetMathGrid::getStatus(cur, cmd, flag); + } + default: + return InsetMathGrid::getStatus(cur, cmd, flag); + } +} + + +void InsetMathSplit::write(WriteStream & ws) const +{ + if (ws.fragile()) + ws << "\\protect"; + ws << "\\begin{" << name_ << '}'; + if (name_ != "split" && valign() != 'c') + ws << '[' << valign() << ']'; + if (name_ == "alignedat") + ws << '{' << static_cast((ncols() + 1)/2) << '}'; + InsetMathGrid::write(ws); + if (ws.fragile()) + ws << "\\protect"; + ws << "\\end{" << name_ << "}\n"; +} + + +void InsetMathSplit::infoize(odocstream & os) const +{ + docstring name = name_; + name[0] = support::uppercase(name[0]); + os << name << ' '; +} + + +void InsetMathSplit::validate(LaTeXFeatures & features) const +{ + if (name_ == "split" || name_ == "gathered" || name_ == "aligned" || + name_ == "alignedat") + features.require("amsmath"); + InsetMathGrid::validate(features); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathSqrt.C b/src/mathed/InsetMathSqrt.C deleted file mode 100644 index 55d773c946..0000000000 --- a/src/mathed/InsetMathSqrt.C +++ /dev/null @@ -1,118 +0,0 @@ -/** - * \file InsetMathSqrt.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathSqrt.h" -#include "MathData.h" -#include "MathStream.h" -#include "TextPainter.h" -#include "LColor.h" -#include "frontends/Painter.h" - - -namespace lyx { - -using std::auto_ptr; - - -InsetMathSqrt::InsetMathSqrt() - : InsetMathNest(1) -{} - - -auto_ptr InsetMathSqrt::doClone() const -{ - return auto_ptr(new InsetMathSqrt(*this)); -} - - -bool InsetMathSqrt::metrics(MetricsInfo & mi, Dimension & dim) const -{ - cell(0).metrics(mi, dim); - dim.asc += 4; - dim.des += 2; - dim.wid += 12; - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathSqrt::draw(PainterInfo & pi, int x, int y) const -{ - cell(0).draw(pi, x + 10, y); - int const a = dim_.ascent(); - int const d = dim_.descent(); - int xp[4]; - int yp[4]; - xp[0] = x + dim_.width(); yp[0] = y - a + 1; - xp[1] = x + 8; yp[1] = y - a + 1; - xp[2] = x + 5; yp[2] = y + d - 1; - xp[3] = x; yp[3] = y + (d - a)/2; - pi.pain.lines(xp, yp, 4, LColor::math); - drawMarkers(pi, x, y); -} - - -void InsetMathSqrt::metricsT(TextMetricsInfo const & mi, Dimension & dim) const -{ - cell(0).metricsT(mi, dim); - dim.asc += 1; - dim.wid += 2; -} - - -void InsetMathSqrt::drawT(TextPainter & pain, int x, int y) const -{ - cell(0).drawT(pain, x + 2, y); - pain.horizontalLine(x + 2, y - cell(0).ascent(), cell(0).width(), '_'); - pain.verticalLine (x + 1, y - cell(0).ascent() + 1, cell(0).height()); - pain.draw(x, y + cell(0).descent(), '\\'); -} - - -void InsetMathSqrt::write(WriteStream & os) const -{ - os << "\\sqrt{" << cell(0) << '}'; -} - - -void InsetMathSqrt::normalize(NormalStream & os) const -{ - os << "[sqrt " << cell(0) << ']'; -} - -void InsetMathSqrt::maple(MapleStream & os) const -{ - os << "sqrt(" << cell(0) << ')'; -} - -void InsetMathSqrt::mathematica(MathematicaStream & os) const -{ - os << "Sqrt[" << cell(0) << ']'; -} - - -void InsetMathSqrt::octave(OctaveStream & os) const -{ - os << "sqrt(" << cell(0) << ')'; -} - - -void InsetMathSqrt::mathmlize(MathStream & os) const -{ - os << MTag("msqrt") << cell(0) << ETag("msqrt"); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathSqrt.cpp b/src/mathed/InsetMathSqrt.cpp new file mode 100644 index 0000000000..55d773c946 --- /dev/null +++ b/src/mathed/InsetMathSqrt.cpp @@ -0,0 +1,118 @@ +/** + * \file InsetMathSqrt.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathSqrt.h" +#include "MathData.h" +#include "MathStream.h" +#include "TextPainter.h" +#include "LColor.h" +#include "frontends/Painter.h" + + +namespace lyx { + +using std::auto_ptr; + + +InsetMathSqrt::InsetMathSqrt() + : InsetMathNest(1) +{} + + +auto_ptr InsetMathSqrt::doClone() const +{ + return auto_ptr(new InsetMathSqrt(*this)); +} + + +bool InsetMathSqrt::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(0).metrics(mi, dim); + dim.asc += 4; + dim.des += 2; + dim.wid += 12; + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathSqrt::draw(PainterInfo & pi, int x, int y) const +{ + cell(0).draw(pi, x + 10, y); + int const a = dim_.ascent(); + int const d = dim_.descent(); + int xp[4]; + int yp[4]; + xp[0] = x + dim_.width(); yp[0] = y - a + 1; + xp[1] = x + 8; yp[1] = y - a + 1; + xp[2] = x + 5; yp[2] = y + d - 1; + xp[3] = x; yp[3] = y + (d - a)/2; + pi.pain.lines(xp, yp, 4, LColor::math); + drawMarkers(pi, x, y); +} + + +void InsetMathSqrt::metricsT(TextMetricsInfo const & mi, Dimension & dim) const +{ + cell(0).metricsT(mi, dim); + dim.asc += 1; + dim.wid += 2; +} + + +void InsetMathSqrt::drawT(TextPainter & pain, int x, int y) const +{ + cell(0).drawT(pain, x + 2, y); + pain.horizontalLine(x + 2, y - cell(0).ascent(), cell(0).width(), '_'); + pain.verticalLine (x + 1, y - cell(0).ascent() + 1, cell(0).height()); + pain.draw(x, y + cell(0).descent(), '\\'); +} + + +void InsetMathSqrt::write(WriteStream & os) const +{ + os << "\\sqrt{" << cell(0) << '}'; +} + + +void InsetMathSqrt::normalize(NormalStream & os) const +{ + os << "[sqrt " << cell(0) << ']'; +} + +void InsetMathSqrt::maple(MapleStream & os) const +{ + os << "sqrt(" << cell(0) << ')'; +} + +void InsetMathSqrt::mathematica(MathematicaStream & os) const +{ + os << "Sqrt[" << cell(0) << ']'; +} + + +void InsetMathSqrt::octave(OctaveStream & os) const +{ + os << "sqrt(" << cell(0) << ')'; +} + + +void InsetMathSqrt::mathmlize(MathStream & os) const +{ + os << MTag("msqrt") << cell(0) << ETag("msqrt"); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathStackrel.C b/src/mathed/InsetMathStackrel.C deleted file mode 100644 index 9f1a9baba9..0000000000 --- a/src/mathed/InsetMathStackrel.C +++ /dev/null @@ -1,74 +0,0 @@ -/** - * \file InsetMathStackrel.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathStackrel.h" -#include "MathData.h" -#include "MathStream.h" - - -namespace lyx { - - -using std::max; -using std::auto_ptr; - - -InsetMathStackrel::InsetMathStackrel() -{} - - -auto_ptr InsetMathStackrel::doClone() const -{ - return auto_ptr(new InsetMathStackrel(*this)); -} - - -bool InsetMathStackrel::metrics(MetricsInfo & mi, Dimension & dim) const -{ - cell(1).metrics(mi); - FracChanger dummy(mi.base); - cell(0).metrics(mi); - dim.wid = max(cell(0).width(), cell(1).width()) + 4; - dim.asc = cell(1).ascent() + cell(0).height() + 4; - dim.des = cell(1).descent(); - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathStackrel::draw(PainterInfo & pi, int x, int y) const -{ - int m = x + dim_.width() / 2; - int yo = y - cell(1).ascent() - cell(0).descent() - 1; - cell(1).draw(pi, m - cell(1).width() / 2, y); - FracChanger dummy(pi.base); - cell(0).draw(pi, m - cell(0).width() / 2, yo); - drawMarkers(pi, x, y); -} - - -void InsetMathStackrel::write(WriteStream & os) const -{ - os << "\\stackrel{" << cell(0) << "}{" << cell(1) << '}'; -} - - -void InsetMathStackrel::normalize(NormalStream & os) const -{ - os << "[stackrel " << cell(0) << ' ' << cell(1) << ']'; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathStackrel.cpp b/src/mathed/InsetMathStackrel.cpp new file mode 100644 index 0000000000..9f1a9baba9 --- /dev/null +++ b/src/mathed/InsetMathStackrel.cpp @@ -0,0 +1,74 @@ +/** + * \file InsetMathStackrel.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathStackrel.h" +#include "MathData.h" +#include "MathStream.h" + + +namespace lyx { + + +using std::max; +using std::auto_ptr; + + +InsetMathStackrel::InsetMathStackrel() +{} + + +auto_ptr InsetMathStackrel::doClone() const +{ + return auto_ptr(new InsetMathStackrel(*this)); +} + + +bool InsetMathStackrel::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(1).metrics(mi); + FracChanger dummy(mi.base); + cell(0).metrics(mi); + dim.wid = max(cell(0).width(), cell(1).width()) + 4; + dim.asc = cell(1).ascent() + cell(0).height() + 4; + dim.des = cell(1).descent(); + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathStackrel::draw(PainterInfo & pi, int x, int y) const +{ + int m = x + dim_.width() / 2; + int yo = y - cell(1).ascent() - cell(0).descent() - 1; + cell(1).draw(pi, m - cell(1).width() / 2, y); + FracChanger dummy(pi.base); + cell(0).draw(pi, m - cell(0).width() / 2, yo); + drawMarkers(pi, x, y); +} + + +void InsetMathStackrel::write(WriteStream & os) const +{ + os << "\\stackrel{" << cell(0) << "}{" << cell(1) << '}'; +} + + +void InsetMathStackrel::normalize(NormalStream & os) const +{ + os << "[stackrel " << cell(0) << ' ' << cell(1) << ']'; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathString.C b/src/mathed/InsetMathString.C deleted file mode 100644 index ab4a13704e..0000000000 --- a/src/mathed/InsetMathString.C +++ /dev/null @@ -1,113 +0,0 @@ -/** - * \file InsetMathString.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathString.h" -#include "MathStream.h" -#include "MathStream.h" -#include "MathSupport.h" - - -namespace lyx { - -using std::auto_ptr; -using std::vector; - - -InsetMathString::InsetMathString(docstring const & s) - : str_(s) -{} - - -auto_ptr InsetMathString::doClone() const -{ - return auto_ptr(new InsetMathString(*this)); -} - - -bool InsetMathString::metrics(MetricsInfo & mi, Dimension & dim) const -{ - mathed_string_dim(mi.base.font, str_, dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathString::draw(PainterInfo & pi, int x, int y) const -{ - pi.draw(x, y, str_); -} - - -void InsetMathString::normalize(NormalStream & os) const -{ - os << "[string " << str_ << ' ' << "mathalpha" << ']'; -} - - -void InsetMathString::maple(MapleStream & os) const -{ - if (/*code_ != LM_TC_VAR ||*/ str_.size() <= 1) { - os << ' ' << str_ << ' '; - return; - } - - // insert '*' between adjacent chars if type is LM_TC_VAR - os << str_[0]; - for (size_t i = 1; i < str_.size(); ++i) - os << str_[i]; -} - - -void InsetMathString::mathematica(MathematicaStream & os) const -{ - os << ' ' << str_ << ' '; -} - - -void InsetMathString::octave(OctaveStream & os) const -{ - if (/*code_ != LM_TC_VAR ||*/ str_.size() <= 1) { - os << ' ' << str_ << ' '; - return; - } - - // insert '*' between adjacent chars if type is LM_TC_VAR - os << str_[0]; - for (size_t i = 1; i < str_.size(); ++i) - os << str_[i]; -} - - -void InsetMathString::mathmlize(MathStream & os) const -{ -/* - if (code_ == LM_TC_VAR) - os << " " << str_ << " "; - else if (code_ == LM_TC_CONST) - os << " " << str_ << " "; - else if (code_ == LM_TC_RM || code_ == LM_TC_TEXTRM) - os << " " << str_ << " "; - else -*/ - os << str_; -} - - -void InsetMathString::write(WriteStream & os) const -{ - os << str_; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathString.cpp b/src/mathed/InsetMathString.cpp new file mode 100644 index 0000000000..ab4a13704e --- /dev/null +++ b/src/mathed/InsetMathString.cpp @@ -0,0 +1,113 @@ +/** + * \file InsetMathString.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathString.h" +#include "MathStream.h" +#include "MathStream.h" +#include "MathSupport.h" + + +namespace lyx { + +using std::auto_ptr; +using std::vector; + + +InsetMathString::InsetMathString(docstring const & s) + : str_(s) +{} + + +auto_ptr InsetMathString::doClone() const +{ + return auto_ptr(new InsetMathString(*this)); +} + + +bool InsetMathString::metrics(MetricsInfo & mi, Dimension & dim) const +{ + mathed_string_dim(mi.base.font, str_, dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathString::draw(PainterInfo & pi, int x, int y) const +{ + pi.draw(x, y, str_); +} + + +void InsetMathString::normalize(NormalStream & os) const +{ + os << "[string " << str_ << ' ' << "mathalpha" << ']'; +} + + +void InsetMathString::maple(MapleStream & os) const +{ + if (/*code_ != LM_TC_VAR ||*/ str_.size() <= 1) { + os << ' ' << str_ << ' '; + return; + } + + // insert '*' between adjacent chars if type is LM_TC_VAR + os << str_[0]; + for (size_t i = 1; i < str_.size(); ++i) + os << str_[i]; +} + + +void InsetMathString::mathematica(MathematicaStream & os) const +{ + os << ' ' << str_ << ' '; +} + + +void InsetMathString::octave(OctaveStream & os) const +{ + if (/*code_ != LM_TC_VAR ||*/ str_.size() <= 1) { + os << ' ' << str_ << ' '; + return; + } + + // insert '*' between adjacent chars if type is LM_TC_VAR + os << str_[0]; + for (size_t i = 1; i < str_.size(); ++i) + os << str_[i]; +} + + +void InsetMathString::mathmlize(MathStream & os) const +{ +/* + if (code_ == LM_TC_VAR) + os << " " << str_ << " "; + else if (code_ == LM_TC_CONST) + os << " " << str_ << " "; + else if (code_ == LM_TC_RM || code_ == LM_TC_TEXTRM) + os << " " << str_ << " "; + else +*/ + os << str_; +} + + +void InsetMathString::write(WriteStream & os) const +{ + os << str_; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathSubstack.C b/src/mathed/InsetMathSubstack.C deleted file mode 100644 index ef494f7f45..0000000000 --- a/src/mathed/InsetMathSubstack.C +++ /dev/null @@ -1,124 +0,0 @@ -/** - * \file InsetMathSubstack.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "LaTeXFeatures.h" -#include "InsetMathSubstack.h" -#include "MathData.h" -#include "MathStream.h" -#include "support/std_ostream.h" - -#include "funcrequest.h" -#include "FuncStatus.h" -#include "gettext.h" - -#include "support/lstrings.h" - - -namespace lyx { - -using support::bformat; - -using std::string; -using std::auto_ptr; - - -InsetMathSubstack::InsetMathSubstack() - : InsetMathGrid(1, 1) -{} - - -auto_ptr InsetMathSubstack::doClone() const -{ - return auto_ptr(new InsetMathSubstack(*this)); -} - - -bool InsetMathSubstack::metrics(MetricsInfo & mi, Dimension & dim) const -{ - if (mi.base.style == LM_ST_DISPLAY) { - StyleChanger dummy(mi.base, LM_ST_TEXT); - InsetMathGrid::metrics(mi, dim); - } else { - InsetMathGrid::metrics(mi, dim); - } - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathSubstack::draw(PainterInfo & pi, int x, int y) const -{ - InsetMathGrid::draw(pi, x + 1, y); -} - - -bool InsetMathSubstack::getStatus(LCursor & cur, FuncRequest const & cmd, - FuncStatus & flag) const -{ - switch (cmd.action) { - case LFUN_TABULAR_FEATURE: { - string const name("substack"); - docstring const & s = cmd.argument(); - if (s == "add-vline-left" || s == "add-vline-right") { - flag.message(bformat( - from_utf8(N_("Can't add vertical grid lines in '%1$s'")), lyx::from_utf8(name))); - flag.enabled(false); - return true; - } - return InsetMathGrid::getStatus(cur, cmd, flag); - } - default: - return InsetMathGrid::getStatus(cur, cmd, flag); - } -} - - -void InsetMathSubstack::infoize(odocstream & os) const -{ - os << "Substack "; -} - - -void InsetMathSubstack::write(WriteStream & os) const -{ - os << "\\substack{"; - InsetMathGrid::write(os); - os << "}\n"; -} - - -void InsetMathSubstack::normalize(NormalStream & os) const -{ - os << "[substack "; - InsetMathGrid::normalize(os); - os << ']'; -} - - -void InsetMathSubstack::maple(MapleStream & os) const -{ - os << "substack("; - InsetMathGrid::maple(os); - os << ')'; -} - - -void InsetMathSubstack::validate(LaTeXFeatures & features) const -{ - features.require("amsmath"); - InsetMathGrid::validate(features); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathSubstack.cpp b/src/mathed/InsetMathSubstack.cpp new file mode 100644 index 0000000000..ef494f7f45 --- /dev/null +++ b/src/mathed/InsetMathSubstack.cpp @@ -0,0 +1,124 @@ +/** + * \file InsetMathSubstack.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "LaTeXFeatures.h" +#include "InsetMathSubstack.h" +#include "MathData.h" +#include "MathStream.h" +#include "support/std_ostream.h" + +#include "funcrequest.h" +#include "FuncStatus.h" +#include "gettext.h" + +#include "support/lstrings.h" + + +namespace lyx { + +using support::bformat; + +using std::string; +using std::auto_ptr; + + +InsetMathSubstack::InsetMathSubstack() + : InsetMathGrid(1, 1) +{} + + +auto_ptr InsetMathSubstack::doClone() const +{ + return auto_ptr(new InsetMathSubstack(*this)); +} + + +bool InsetMathSubstack::metrics(MetricsInfo & mi, Dimension & dim) const +{ + if (mi.base.style == LM_ST_DISPLAY) { + StyleChanger dummy(mi.base, LM_ST_TEXT); + InsetMathGrid::metrics(mi, dim); + } else { + InsetMathGrid::metrics(mi, dim); + } + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathSubstack::draw(PainterInfo & pi, int x, int y) const +{ + InsetMathGrid::draw(pi, x + 1, y); +} + + +bool InsetMathSubstack::getStatus(LCursor & cur, FuncRequest const & cmd, + FuncStatus & flag) const +{ + switch (cmd.action) { + case LFUN_TABULAR_FEATURE: { + string const name("substack"); + docstring const & s = cmd.argument(); + if (s == "add-vline-left" || s == "add-vline-right") { + flag.message(bformat( + from_utf8(N_("Can't add vertical grid lines in '%1$s'")), lyx::from_utf8(name))); + flag.enabled(false); + return true; + } + return InsetMathGrid::getStatus(cur, cmd, flag); + } + default: + return InsetMathGrid::getStatus(cur, cmd, flag); + } +} + + +void InsetMathSubstack::infoize(odocstream & os) const +{ + os << "Substack "; +} + + +void InsetMathSubstack::write(WriteStream & os) const +{ + os << "\\substack{"; + InsetMathGrid::write(os); + os << "}\n"; +} + + +void InsetMathSubstack::normalize(NormalStream & os) const +{ + os << "[substack "; + InsetMathGrid::normalize(os); + os << ']'; +} + + +void InsetMathSubstack::maple(MapleStream & os) const +{ + os << "substack("; + InsetMathGrid::maple(os); + os << ')'; +} + + +void InsetMathSubstack::validate(LaTeXFeatures & features) const +{ + features.require("amsmath"); + InsetMathGrid::validate(features); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathSymbol.C b/src/mathed/InsetMathSymbol.C deleted file mode 100644 index 87aff39550..0000000000 --- a/src/mathed/InsetMathSymbol.C +++ /dev/null @@ -1,240 +0,0 @@ -/** - * \file InsetMathSymbol.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathSymbol.h" -#include "dimension.h" -#include "MathStream.h" -#include "MathStream.h" -#include "MathSupport.h" -#include "MathParser.h" -#include "MathAtom.h" -#include "LaTeXFeatures.h" -#include "debug.h" - -#include "support/textutils.h" - -namespace lyx { - -using std::string; -using std::auto_ptr; - - -InsetMathSymbol::InsetMathSymbol(latexkeys const * l) - : sym_(l), h_(0), scriptable_(false), font_cache_(LyXFont::ALL_IGNORE) -{} - - -InsetMathSymbol::InsetMathSymbol(char const * name) - : sym_(in_word_set(from_ascii(name))), h_(0), scriptable_(false), - font_cache_(LyXFont::ALL_IGNORE) -{} - - -InsetMathSymbol::InsetMathSymbol(docstring const & name) - : sym_(in_word_set(name)), h_(0), scriptable_(false), font_cache_(LyXFont::ALL_IGNORE) -{} - - -auto_ptr InsetMathSymbol::doClone() const -{ - return auto_ptr(new InsetMathSymbol(*this)); -} - - -docstring InsetMathSymbol::name() const -{ - return sym_->name; -} - - -bool InsetMathSymbol::metrics(MetricsInfo & mi, Dimension & dim) const -{ - //lyxerr << "metrics: symbol: '" << sym_->name - // << "' in font: '" << sym_->inset - // << "' drawn as: '" << sym_->draw - // << "'" << std::endl; - - bool dim_unchanged = (mi.base.font == font_cache_); - if (dim_unchanged) - dim = dim_; - else { - font_cache_ = mi.base.font; - int const em = mathed_char_width(mi.base.font, 'M'); - FontSetChanger dummy(mi.base, sym_->inset); - mathed_string_dim(mi.base.font, sym_->draw, dim); - docstring::const_reverse_iterator rit = sym_->draw.rbegin(); - kerning_ = mathed_char_kerning(mi.base.font, *rit); - // correct height for broken cmex and wasy font - if (sym_->inset == "cmex" || sym_->inset == "wasy") { - h_ = 4 * dim.des / 5; - dim.asc += h_; - dim.des -= h_; - } - // seperate things a bit - if (isRelOp()) - dim.wid += static_cast(0.5 * em + 0.5); - else - dim.wid += static_cast(0.1667 * em + 0.5); - - dim_ = dim; - } - - scriptable_ = false; - if (mi.base.style == LM_ST_DISPLAY) - if (sym_->inset == "cmex" || sym_->inset == "esint" || - sym_->extra == "funclim") - scriptable_ = true; - - return dim_unchanged; -} - - -void InsetMathSymbol::draw(PainterInfo & pi, int x, int y) const -{ - //lyxerr << "metrics: symbol: '" << sym_->name - // << "' in font: '" << sym_->inset - // << "' drawn as: '" << sym_->draw - // << "'" << std::endl; - int const em = mathed_char_width(pi.base.font, 'M'); - if (isRelOp()) - x += static_cast(0.25*em+0.5); - else - x += static_cast(0.0833*em+0.5); - - FontSetChanger dummy(pi.base, sym_->inset.c_str()); - pi.draw(x, y - h_, sym_->draw); -} - - -bool InsetMathSymbol::isRelOp() const -{ - return sym_->extra == "mathrel"; -} - - -bool InsetMathSymbol::isOrdAlpha() const -{ - return sym_->extra == "mathord" || sym_->extra == "mathalpha"; -} - - -bool InsetMathSymbol::isScriptable() const -{ - return scriptable_; -} - - -bool InsetMathSymbol::takesLimits() const -{ - return - sym_->inset == "cmex" || - sym_->inset == "lyxboldsymb" || - sym_->inset == "esint" || - sym_->extra == "funclim"; -} - - -void InsetMathSymbol::validate(LaTeXFeatures & features) const -{ - if (!sym_->requires.empty()) - features.require(to_utf8(sym_->requires)); -} - - -void InsetMathSymbol::normalize(NormalStream & os) const -{ - os << "[symbol " << name() << ']'; -} - - -void InsetMathSymbol::maple(MapleStream & os) const -{ - if (name() == "cdot") - os << '*'; - else if (name() == "infty") - os << "infinity"; - else - os << name(); -} - -void InsetMathSymbol::maxima(MaximaStream & os) const -{ - if (name() == "cdot") - os << '*'; - else if (name() == "infty") - os << "inf"; - else if (name() == "pi") - os << "%pi"; - else - os << name(); -} - - -void InsetMathSymbol::mathematica(MathematicaStream & os) const -{ - if ( name() == "pi") { os << "Pi"; return;} - if ( name() == "infty") { os << "Infinity"; return;} - if ( name() == "cdot") { os << '*'; return;} - os << name(); -} - - -char const * MathMLtype(docstring const & s) -{ - if (s == "mathop") - return "mo"; - return "mi"; -} - - -void InsetMathSymbol::mathmlize(MathStream & os) const -{ - char const * type = MathMLtype(sym_->extra); - os << '<' << type << "> "; - if (sym_->xmlname == "x") // unknown so far - os << name(); - else - os << sym_->xmlname; - os << " '; -} - - -void InsetMathSymbol::octave(OctaveStream & os) const -{ - if (name() == "cdot") - os << '*'; - else - os << name(); -} - - -void InsetMathSymbol::write(WriteStream & os) const -{ - os << '\\' << name(); - - // $,#, etc. In theory the restriction based on catcodes, but then - // we do not handle catcodes very well, let alone cat code changes, - // so being outside the alpha range is good enough. - if (name().size() == 1 && !isAlphaASCII(name()[0])) - return; - - os.pendingSpace(true); -} - - -void InsetMathSymbol::infoize2(odocstream & os) const -{ - os << "Symbol: " << name(); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathSymbol.cpp b/src/mathed/InsetMathSymbol.cpp new file mode 100644 index 0000000000..87aff39550 --- /dev/null +++ b/src/mathed/InsetMathSymbol.cpp @@ -0,0 +1,240 @@ +/** + * \file InsetMathSymbol.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathSymbol.h" +#include "dimension.h" +#include "MathStream.h" +#include "MathStream.h" +#include "MathSupport.h" +#include "MathParser.h" +#include "MathAtom.h" +#include "LaTeXFeatures.h" +#include "debug.h" + +#include "support/textutils.h" + +namespace lyx { + +using std::string; +using std::auto_ptr; + + +InsetMathSymbol::InsetMathSymbol(latexkeys const * l) + : sym_(l), h_(0), scriptable_(false), font_cache_(LyXFont::ALL_IGNORE) +{} + + +InsetMathSymbol::InsetMathSymbol(char const * name) + : sym_(in_word_set(from_ascii(name))), h_(0), scriptable_(false), + font_cache_(LyXFont::ALL_IGNORE) +{} + + +InsetMathSymbol::InsetMathSymbol(docstring const & name) + : sym_(in_word_set(name)), h_(0), scriptable_(false), font_cache_(LyXFont::ALL_IGNORE) +{} + + +auto_ptr InsetMathSymbol::doClone() const +{ + return auto_ptr(new InsetMathSymbol(*this)); +} + + +docstring InsetMathSymbol::name() const +{ + return sym_->name; +} + + +bool InsetMathSymbol::metrics(MetricsInfo & mi, Dimension & dim) const +{ + //lyxerr << "metrics: symbol: '" << sym_->name + // << "' in font: '" << sym_->inset + // << "' drawn as: '" << sym_->draw + // << "'" << std::endl; + + bool dim_unchanged = (mi.base.font == font_cache_); + if (dim_unchanged) + dim = dim_; + else { + font_cache_ = mi.base.font; + int const em = mathed_char_width(mi.base.font, 'M'); + FontSetChanger dummy(mi.base, sym_->inset); + mathed_string_dim(mi.base.font, sym_->draw, dim); + docstring::const_reverse_iterator rit = sym_->draw.rbegin(); + kerning_ = mathed_char_kerning(mi.base.font, *rit); + // correct height for broken cmex and wasy font + if (sym_->inset == "cmex" || sym_->inset == "wasy") { + h_ = 4 * dim.des / 5; + dim.asc += h_; + dim.des -= h_; + } + // seperate things a bit + if (isRelOp()) + dim.wid += static_cast(0.5 * em + 0.5); + else + dim.wid += static_cast(0.1667 * em + 0.5); + + dim_ = dim; + } + + scriptable_ = false; + if (mi.base.style == LM_ST_DISPLAY) + if (sym_->inset == "cmex" || sym_->inset == "esint" || + sym_->extra == "funclim") + scriptable_ = true; + + return dim_unchanged; +} + + +void InsetMathSymbol::draw(PainterInfo & pi, int x, int y) const +{ + //lyxerr << "metrics: symbol: '" << sym_->name + // << "' in font: '" << sym_->inset + // << "' drawn as: '" << sym_->draw + // << "'" << std::endl; + int const em = mathed_char_width(pi.base.font, 'M'); + if (isRelOp()) + x += static_cast(0.25*em+0.5); + else + x += static_cast(0.0833*em+0.5); + + FontSetChanger dummy(pi.base, sym_->inset.c_str()); + pi.draw(x, y - h_, sym_->draw); +} + + +bool InsetMathSymbol::isRelOp() const +{ + return sym_->extra == "mathrel"; +} + + +bool InsetMathSymbol::isOrdAlpha() const +{ + return sym_->extra == "mathord" || sym_->extra == "mathalpha"; +} + + +bool InsetMathSymbol::isScriptable() const +{ + return scriptable_; +} + + +bool InsetMathSymbol::takesLimits() const +{ + return + sym_->inset == "cmex" || + sym_->inset == "lyxboldsymb" || + sym_->inset == "esint" || + sym_->extra == "funclim"; +} + + +void InsetMathSymbol::validate(LaTeXFeatures & features) const +{ + if (!sym_->requires.empty()) + features.require(to_utf8(sym_->requires)); +} + + +void InsetMathSymbol::normalize(NormalStream & os) const +{ + os << "[symbol " << name() << ']'; +} + + +void InsetMathSymbol::maple(MapleStream & os) const +{ + if (name() == "cdot") + os << '*'; + else if (name() == "infty") + os << "infinity"; + else + os << name(); +} + +void InsetMathSymbol::maxima(MaximaStream & os) const +{ + if (name() == "cdot") + os << '*'; + else if (name() == "infty") + os << "inf"; + else if (name() == "pi") + os << "%pi"; + else + os << name(); +} + + +void InsetMathSymbol::mathematica(MathematicaStream & os) const +{ + if ( name() == "pi") { os << "Pi"; return;} + if ( name() == "infty") { os << "Infinity"; return;} + if ( name() == "cdot") { os << '*'; return;} + os << name(); +} + + +char const * MathMLtype(docstring const & s) +{ + if (s == "mathop") + return "mo"; + return "mi"; +} + + +void InsetMathSymbol::mathmlize(MathStream & os) const +{ + char const * type = MathMLtype(sym_->extra); + os << '<' << type << "> "; + if (sym_->xmlname == "x") // unknown so far + os << name(); + else + os << sym_->xmlname; + os << " '; +} + + +void InsetMathSymbol::octave(OctaveStream & os) const +{ + if (name() == "cdot") + os << '*'; + else + os << name(); +} + + +void InsetMathSymbol::write(WriteStream & os) const +{ + os << '\\' << name(); + + // $,#, etc. In theory the restriction based on catcodes, but then + // we do not handle catcodes very well, let alone cat code changes, + // so being outside the alpha range is good enough. + if (name().size() == 1 && !isAlphaASCII(name()[0])) + return; + + os.pendingSpace(true); +} + + +void InsetMathSymbol::infoize2(odocstream & os) const +{ + os << "Symbol: " << name(); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathTFrac.C b/src/mathed/InsetMathTFrac.C deleted file mode 100644 index 84ed2b8157..0000000000 --- a/src/mathed/InsetMathTFrac.C +++ /dev/null @@ -1,88 +0,0 @@ -/** - * \file InsetMathDFrac.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathTFrac.h" - -#include "MathData.h" -#include "MathStream.h" - -#include "LaTeXFeatures.h" -#include "LColor.h" - -#include "frontends/Painter.h" - - -namespace lyx { - - -using std::string; -using std::max; -using std::auto_ptr; - - -InsetMathTFrac::InsetMathTFrac() - : InsetMathFrac() -{} - - -auto_ptr InsetMathTFrac::doClone() const -{ - return auto_ptr(new InsetMathTFrac(*this)); -} - - -bool InsetMathTFrac::metrics(MetricsInfo & mi, Dimension & dim) const -{ - StyleChanger dummy(mi.base, LM_ST_SCRIPT); - cell(0).metrics(mi); - cell(1).metrics(mi); - dim.wid = max(cell(0).width(), cell(1).width()) + 2; - dim.asc = cell(0).height() + 2 + 5; - dim.des = cell(1).height() + 2 - 5; - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathTFrac::draw(PainterInfo & pi, int x, int y) const -{ - StyleChanger dummy(pi.base, LM_ST_SCRIPT); - int m = x + dim_.wid / 2; - cell(0).draw(pi, m - cell(0).width() / 2, y - cell(0).descent() - 2 - 5); - cell(1).draw(pi, m - cell(1).width() / 2, y + cell(1).ascent() + 2 - 5); - pi.pain.line(x + 1, y - 5, x + dim_.wid - 2, y - 5, LColor::math); - setPosCache(pi, x, y); -} - - -docstring InsetMathTFrac::name() const -{ - return from_ascii("tfrac"); -} - - -void InsetMathTFrac::mathmlize(MathStream & os) const -{ - os << MTag("mtfrac") << cell(0) << cell(1) << ETag("mtfrac"); -} - - -void InsetMathTFrac::validate(LaTeXFeatures & features) const -{ - features.require("amsmath"); - InsetMathNest::validate(features); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathTFrac.cpp b/src/mathed/InsetMathTFrac.cpp new file mode 100644 index 0000000000..84ed2b8157 --- /dev/null +++ b/src/mathed/InsetMathTFrac.cpp @@ -0,0 +1,88 @@ +/** + * \file InsetMathDFrac.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathTFrac.h" + +#include "MathData.h" +#include "MathStream.h" + +#include "LaTeXFeatures.h" +#include "LColor.h" + +#include "frontends/Painter.h" + + +namespace lyx { + + +using std::string; +using std::max; +using std::auto_ptr; + + +InsetMathTFrac::InsetMathTFrac() + : InsetMathFrac() +{} + + +auto_ptr InsetMathTFrac::doClone() const +{ + return auto_ptr(new InsetMathTFrac(*this)); +} + + +bool InsetMathTFrac::metrics(MetricsInfo & mi, Dimension & dim) const +{ + StyleChanger dummy(mi.base, LM_ST_SCRIPT); + cell(0).metrics(mi); + cell(1).metrics(mi); + dim.wid = max(cell(0).width(), cell(1).width()) + 2; + dim.asc = cell(0).height() + 2 + 5; + dim.des = cell(1).height() + 2 - 5; + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathTFrac::draw(PainterInfo & pi, int x, int y) const +{ + StyleChanger dummy(pi.base, LM_ST_SCRIPT); + int m = x + dim_.wid / 2; + cell(0).draw(pi, m - cell(0).width() / 2, y - cell(0).descent() - 2 - 5); + cell(1).draw(pi, m - cell(1).width() / 2, y + cell(1).ascent() + 2 - 5); + pi.pain.line(x + 1, y - 5, x + dim_.wid - 2, y - 5, LColor::math); + setPosCache(pi, x, y); +} + + +docstring InsetMathTFrac::name() const +{ + return from_ascii("tfrac"); +} + + +void InsetMathTFrac::mathmlize(MathStream & os) const +{ + os << MTag("mtfrac") << cell(0) << cell(1) << ETag("mtfrac"); +} + + +void InsetMathTFrac::validate(LaTeXFeatures & features) const +{ + features.require("amsmath"); + InsetMathNest::validate(features); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathTabular.C b/src/mathed/InsetMathTabular.C deleted file mode 100644 index 7445044e3e..0000000000 --- a/src/mathed/InsetMathTabular.C +++ /dev/null @@ -1,117 +0,0 @@ -/** - * \file InsetMathTabular.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathTabular.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathStream.h" - -#include "support/lstrings.h" -#include "support/std_ostream.h" - -#include - - -namespace lyx { - - -using std::string; -using std::auto_ptr; - - -InsetMathTabular::InsetMathTabular(docstring const & name, int m, int n) - : InsetMathGrid(m, n), name_(name) -{} - - -InsetMathTabular::InsetMathTabular(docstring const & name, int m, int n, - char valign, docstring const & halign) - : InsetMathGrid(m, n, valign, halign), name_(name) -{} - - -InsetMathTabular::InsetMathTabular(docstring const & name, char valign, - docstring const & halign) - : InsetMathGrid(valign, halign), name_(name) -{} - - -auto_ptr InsetMathTabular::doClone() const -{ - return auto_ptr(new InsetMathTabular(*this)); -} - - -bool InsetMathTabular::metrics(MetricsInfo & mi, Dimension & dim) const -{ - FontSetChanger dummy(mi.base, "textnormal"); - InsetMathGrid::metrics(mi, dim); - dim.wid += 6; - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathTabular::draw(PainterInfo & pi, int x, int y) const -{ - FontSetChanger dummy(pi.base, "textnormal"); - InsetMathGrid::drawWithMargin(pi, x, y, 4, 2); -} - - -void InsetMathTabular::write(WriteStream & os) const -{ - if (os.fragile()) - os << "\\protect"; - os << "\\begin{" << name_ << '}'; - - if (v_align_ == 't' || v_align_ == 'b') - os << '[' << char(v_align_) << ']'; - os << '{' << halign() << "}\n"; - - InsetMathGrid::write(os); - - if (os.fragile()) - os << "\\protect"; - os << "\\end{" << name_ << '}'; - // adding a \n here is bad if the tabular is the last item - // in an \eqnarray... -} - - -void InsetMathTabular::infoize(odocstream & os) const -{ - docstring name = name_; - name[0] = support::uppercase(name[0]); - os << name << ' '; -} - - -void InsetMathTabular::normalize(NormalStream & os) const -{ - os << '[' << name_ << ' '; - InsetMathGrid::normalize(os); - os << ']'; -} - - -void InsetMathTabular::maple(MapleStream & os) const -{ - os << "array("; - InsetMathGrid::maple(os); - os << ')'; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathTabular.cpp b/src/mathed/InsetMathTabular.cpp new file mode 100644 index 0000000000..7445044e3e --- /dev/null +++ b/src/mathed/InsetMathTabular.cpp @@ -0,0 +1,117 @@ +/** + * \file InsetMathTabular.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathTabular.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathStream.h" + +#include "support/lstrings.h" +#include "support/std_ostream.h" + +#include + + +namespace lyx { + + +using std::string; +using std::auto_ptr; + + +InsetMathTabular::InsetMathTabular(docstring const & name, int m, int n) + : InsetMathGrid(m, n), name_(name) +{} + + +InsetMathTabular::InsetMathTabular(docstring const & name, int m, int n, + char valign, docstring const & halign) + : InsetMathGrid(m, n, valign, halign), name_(name) +{} + + +InsetMathTabular::InsetMathTabular(docstring const & name, char valign, + docstring const & halign) + : InsetMathGrid(valign, halign), name_(name) +{} + + +auto_ptr InsetMathTabular::doClone() const +{ + return auto_ptr(new InsetMathTabular(*this)); +} + + +bool InsetMathTabular::metrics(MetricsInfo & mi, Dimension & dim) const +{ + FontSetChanger dummy(mi.base, "textnormal"); + InsetMathGrid::metrics(mi, dim); + dim.wid += 6; + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathTabular::draw(PainterInfo & pi, int x, int y) const +{ + FontSetChanger dummy(pi.base, "textnormal"); + InsetMathGrid::drawWithMargin(pi, x, y, 4, 2); +} + + +void InsetMathTabular::write(WriteStream & os) const +{ + if (os.fragile()) + os << "\\protect"; + os << "\\begin{" << name_ << '}'; + + if (v_align_ == 't' || v_align_ == 'b') + os << '[' << char(v_align_) << ']'; + os << '{' << halign() << "}\n"; + + InsetMathGrid::write(os); + + if (os.fragile()) + os << "\\protect"; + os << "\\end{" << name_ << '}'; + // adding a \n here is bad if the tabular is the last item + // in an \eqnarray... +} + + +void InsetMathTabular::infoize(odocstream & os) const +{ + docstring name = name_; + name[0] = support::uppercase(name[0]); + os << name << ' '; +} + + +void InsetMathTabular::normalize(NormalStream & os) const +{ + os << '[' << name_ << ' '; + InsetMathGrid::normalize(os); + os << ']'; +} + + +void InsetMathTabular::maple(MapleStream & os) const +{ + os << "array("; + InsetMathGrid::maple(os); + os << ')'; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathUnderset.C b/src/mathed/InsetMathUnderset.C deleted file mode 100644 index 577d49e3bb..0000000000 --- a/src/mathed/InsetMathUnderset.C +++ /dev/null @@ -1,107 +0,0 @@ -/** - * \file InsetMathUnderset.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathUnderset.h" -#include "MathData.h" -#include "MathStream.h" - -#include "cursor.h" -#include "LaTeXFeatures.h" - - -namespace lyx { - -using std::max; -using std::auto_ptr; - - - -auto_ptr InsetMathUnderset::doClone() const -{ - return auto_ptr(new InsetMathUnderset(*this)); -} - - -bool InsetMathUnderset::metrics(MetricsInfo & mi, Dimension & dim) const -{ - cell(1).metrics(mi); - FracChanger dummy(mi.base); - cell(0).metrics(mi); - dim.wid = max(cell(0).width(), cell(1).width()) + 4; - dim.asc = cell(1).ascent(); - dim.des = cell(1).descent() + cell(0).height() + 4; - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathUnderset::draw(PainterInfo & pi, int x, int y) const -{ - int m = x + width() / 2; - int yo = y + cell(1).descent() + cell(0).ascent() + 1; - cell(1).draw(pi, m - cell(1).width() / 2, y); - FracChanger dummy(pi.base); - cell(0).draw(pi, m - cell(0).width() / 2, yo); - drawMarkers(pi, x, y); -} - - -bool InsetMathUnderset::idxFirst(LCursor & cur) const -{ - cur.idx() = 1; - cur.pos() = 0; - return true; -} - - -bool InsetMathUnderset::idxLast(LCursor & cur) const -{ - cur.idx() = 1; - cur.pos() = cur.lastpos(); - return true; -} - - -bool InsetMathUnderset::idxUpDown(LCursor & cur, bool up) const -{ - idx_type target = up; // up ? 1 : 0, since upper cell has idx 1 - if (cur.idx() == target) - return false; - cur.idx() = target; - cur.pos() = cur.cell().x2pos(cur.x_target()); - return true; -} - - -void InsetMathUnderset::write(WriteStream & os) const -{ - os << "\\underset{" << cell(0) << "}{" << cell(1) << '}'; -} - - -void InsetMathUnderset::normalize(NormalStream & os) const -{ - os << "[underset " << cell(0) << ' ' << cell(1) << ']'; -} - - -void InsetMathUnderset::validate(LaTeXFeatures & features) const -{ - features.require("amsmath"); - InsetMathNest::validate(features); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathUnderset.cpp b/src/mathed/InsetMathUnderset.cpp new file mode 100644 index 0000000000..577d49e3bb --- /dev/null +++ b/src/mathed/InsetMathUnderset.cpp @@ -0,0 +1,107 @@ +/** + * \file InsetMathUnderset.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathUnderset.h" +#include "MathData.h" +#include "MathStream.h" + +#include "cursor.h" +#include "LaTeXFeatures.h" + + +namespace lyx { + +using std::max; +using std::auto_ptr; + + + +auto_ptr InsetMathUnderset::doClone() const +{ + return auto_ptr(new InsetMathUnderset(*this)); +} + + +bool InsetMathUnderset::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(1).metrics(mi); + FracChanger dummy(mi.base); + cell(0).metrics(mi); + dim.wid = max(cell(0).width(), cell(1).width()) + 4; + dim.asc = cell(1).ascent(); + dim.des = cell(1).descent() + cell(0).height() + 4; + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathUnderset::draw(PainterInfo & pi, int x, int y) const +{ + int m = x + width() / 2; + int yo = y + cell(1).descent() + cell(0).ascent() + 1; + cell(1).draw(pi, m - cell(1).width() / 2, y); + FracChanger dummy(pi.base); + cell(0).draw(pi, m - cell(0).width() / 2, yo); + drawMarkers(pi, x, y); +} + + +bool InsetMathUnderset::idxFirst(LCursor & cur) const +{ + cur.idx() = 1; + cur.pos() = 0; + return true; +} + + +bool InsetMathUnderset::idxLast(LCursor & cur) const +{ + cur.idx() = 1; + cur.pos() = cur.lastpos(); + return true; +} + + +bool InsetMathUnderset::idxUpDown(LCursor & cur, bool up) const +{ + idx_type target = up; // up ? 1 : 0, since upper cell has idx 1 + if (cur.idx() == target) + return false; + cur.idx() = target; + cur.pos() = cur.cell().x2pos(cur.x_target()); + return true; +} + + +void InsetMathUnderset::write(WriteStream & os) const +{ + os << "\\underset{" << cell(0) << "}{" << cell(1) << '}'; +} + + +void InsetMathUnderset::normalize(NormalStream & os) const +{ + os << "[underset " << cell(0) << ' ' << cell(1) << ']'; +} + + +void InsetMathUnderset::validate(LaTeXFeatures & features) const +{ + features.require("amsmath"); + InsetMathNest::validate(features); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathUnknown.C b/src/mathed/InsetMathUnknown.C deleted file mode 100644 index e26e9180ea..0000000000 --- a/src/mathed/InsetMathUnknown.C +++ /dev/null @@ -1,114 +0,0 @@ -/** - * \file InsetMathUnknown.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathUnknown.h" -#include "MathSupport.h" -#include "MathAtom.h" -#include "MathStream.h" -#include "MathStream.h" - - -namespace lyx { - -using std::string; -using std::auto_ptr; -using std::vector; - - -InsetMathUnknown::InsetMathUnknown(docstring const & nm, bool final, bool black) - : name_(nm), final_(final), black_(black) -{} - - -auto_ptr InsetMathUnknown::doClone() const -{ - return auto_ptr(new InsetMathUnknown(*this)); -} - - -docstring InsetMathUnknown::name() const -{ - return name_; -} - - -void InsetMathUnknown::setName(docstring const & name) -{ - name_ = name; -} - - -void InsetMathUnknown::normalize(NormalStream & os) const -{ - os << "[unknown " << name_ << ']'; -} - - -bool InsetMathUnknown::metrics(MetricsInfo & mi, Dimension & dim) const -{ - mathed_string_dim(mi.base.font, name_, dim); - docstring::const_reverse_iterator rit = name_.rbegin(); - kerning_ = mathed_char_kerning(mi.base.font, *rit); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathUnknown::draw(PainterInfo & pi, int x, int y) const -{ - if (black_) - drawStrBlack(pi, x, y, name_); - else - drawStrRed(pi, x, y, name_); - setPosCache(pi, x, y); -} - - -void InsetMathUnknown::finalize() -{ - final_ = true; -} - - -bool InsetMathUnknown::final() const -{ - return final_; -} - - -void InsetMathUnknown::maple(MapleStream & os) const -{ - os << name_; -} - - -void InsetMathUnknown::mathematica(MathematicaStream & os) const -{ - os << name_; -} - - -void InsetMathUnknown::mathmlize(MathStream & os) const -{ - os << MTag("mi") << name_ << ETag("mi"); -} - - -void InsetMathUnknown::octave(OctaveStream & os) const -{ - os << name_; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathUnknown.cpp b/src/mathed/InsetMathUnknown.cpp new file mode 100644 index 0000000000..e26e9180ea --- /dev/null +++ b/src/mathed/InsetMathUnknown.cpp @@ -0,0 +1,114 @@ +/** + * \file InsetMathUnknown.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathUnknown.h" +#include "MathSupport.h" +#include "MathAtom.h" +#include "MathStream.h" +#include "MathStream.h" + + +namespace lyx { + +using std::string; +using std::auto_ptr; +using std::vector; + + +InsetMathUnknown::InsetMathUnknown(docstring const & nm, bool final, bool black) + : name_(nm), final_(final), black_(black) +{} + + +auto_ptr InsetMathUnknown::doClone() const +{ + return auto_ptr(new InsetMathUnknown(*this)); +} + + +docstring InsetMathUnknown::name() const +{ + return name_; +} + + +void InsetMathUnknown::setName(docstring const & name) +{ + name_ = name; +} + + +void InsetMathUnknown::normalize(NormalStream & os) const +{ + os << "[unknown " << name_ << ']'; +} + + +bool InsetMathUnknown::metrics(MetricsInfo & mi, Dimension & dim) const +{ + mathed_string_dim(mi.base.font, name_, dim); + docstring::const_reverse_iterator rit = name_.rbegin(); + kerning_ = mathed_char_kerning(mi.base.font, *rit); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathUnknown::draw(PainterInfo & pi, int x, int y) const +{ + if (black_) + drawStrBlack(pi, x, y, name_); + else + drawStrRed(pi, x, y, name_); + setPosCache(pi, x, y); +} + + +void InsetMathUnknown::finalize() +{ + final_ = true; +} + + +bool InsetMathUnknown::final() const +{ + return final_; +} + + +void InsetMathUnknown::maple(MapleStream & os) const +{ + os << name_; +} + + +void InsetMathUnknown::mathematica(MathematicaStream & os) const +{ + os << name_; +} + + +void InsetMathUnknown::mathmlize(MathStream & os) const +{ + os << MTag("mi") << name_ << ETag("mi"); +} + + +void InsetMathUnknown::octave(OctaveStream & os) const +{ + os << name_; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathXArrow.C b/src/mathed/InsetMathXArrow.C deleted file mode 100644 index dbd16ac31c..0000000000 --- a/src/mathed/InsetMathXArrow.C +++ /dev/null @@ -1,87 +0,0 @@ -/** - * \file InsetMathXArrow.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathXArrow.h" -#include "MathData.h" -#include "MathStream.h" -#include "MathStream.h" -#include "MathSupport.h" - -#include "LaTeXFeatures.h" - - -namespace lyx { - -using std::string; -using std::auto_ptr; - - -InsetMathXArrow::InsetMathXArrow(docstring const & name) - : InsetMathFracBase(), name_(name) -{} - - -auto_ptr InsetMathXArrow::doClone() const -{ - return auto_ptr(new InsetMathXArrow(*this)); -} - - -bool InsetMathXArrow::metrics(MetricsInfo & mi, Dimension & dim) const -{ - ScriptChanger dummy(mi.base); - cell(0).metrics(mi); - cell(1).metrics(mi); - dim.wid = std::max(cell(0).width(), cell(1).width()) + 10; - dim.asc = cell(0).height() + 10; - dim.des = cell(1).height(); - metricsMarkers(dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathXArrow::draw(PainterInfo & pi, int x, int y) const -{ - ScriptChanger dummy(pi.base); - cell(0).draw(pi, x + 5, y - 10); - cell(1).draw(pi, x + 5, y + cell(1).height()); - mathed_draw_deco(pi, x + 1, y - 7, width() - 2, 5, name_); - drawMarkers(pi, x, y); -} - - -void InsetMathXArrow::write(WriteStream & os) const -{ - os << '\\' << name_; - if (cell(1).size()) - os << '[' << cell(1) << ']'; - os << '{' << cell(0) << '}'; -} - - -void InsetMathXArrow::normalize(NormalStream & os) const -{ - os << "[xarrow " << name_ << ' ' << cell(0) << ' ' << cell(1) << ']'; -} - - -void InsetMathXArrow::validate(LaTeXFeatures & features) const -{ - features.require("amsmath"); - InsetMathNest::validate(features); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathXArrow.cpp b/src/mathed/InsetMathXArrow.cpp new file mode 100644 index 0000000000..dbd16ac31c --- /dev/null +++ b/src/mathed/InsetMathXArrow.cpp @@ -0,0 +1,87 @@ +/** + * \file InsetMathXArrow.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathXArrow.h" +#include "MathData.h" +#include "MathStream.h" +#include "MathStream.h" +#include "MathSupport.h" + +#include "LaTeXFeatures.h" + + +namespace lyx { + +using std::string; +using std::auto_ptr; + + +InsetMathXArrow::InsetMathXArrow(docstring const & name) + : InsetMathFracBase(), name_(name) +{} + + +auto_ptr InsetMathXArrow::doClone() const +{ + return auto_ptr(new InsetMathXArrow(*this)); +} + + +bool InsetMathXArrow::metrics(MetricsInfo & mi, Dimension & dim) const +{ + ScriptChanger dummy(mi.base); + cell(0).metrics(mi); + cell(1).metrics(mi); + dim.wid = std::max(cell(0).width(), cell(1).width()) + 10; + dim.asc = cell(0).height() + 10; + dim.des = cell(1).height(); + metricsMarkers(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathXArrow::draw(PainterInfo & pi, int x, int y) const +{ + ScriptChanger dummy(pi.base); + cell(0).draw(pi, x + 5, y - 10); + cell(1).draw(pi, x + 5, y + cell(1).height()); + mathed_draw_deco(pi, x + 1, y - 7, width() - 2, 5, name_); + drawMarkers(pi, x, y); +} + + +void InsetMathXArrow::write(WriteStream & os) const +{ + os << '\\' << name_; + if (cell(1).size()) + os << '[' << cell(1) << ']'; + os << '{' << cell(0) << '}'; +} + + +void InsetMathXArrow::normalize(NormalStream & os) const +{ + os << "[xarrow " << name_ << ' ' << cell(0) << ' ' << cell(1) << ']'; +} + + +void InsetMathXArrow::validate(LaTeXFeatures & features) const +{ + features.require("amsmath"); + InsetMathNest::validate(features); +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathXYArrow.C b/src/mathed/InsetMathXYArrow.C deleted file mode 100644 index fb0f30252d..0000000000 --- a/src/mathed/InsetMathXYArrow.C +++ /dev/null @@ -1,162 +0,0 @@ -/** - * \file InsetMathXYArrow.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathXYArrow.h" -#include "MathStream.h" -#include "MathSupport.h" -#include "frontends/Painter.h" -#include "debug.h" - - -namespace lyx { - - -using std::max; - - -InsetMathXYArrow::InsetMathXYArrow() - : InsetMathNest(2) -{} - - -std::auto_ptr InsetMathXYArrow::clone() const -{ - return std::auto_ptr(new InsetMathXYArrow(*this)); -} - - -InsetMathXYMatrix const * InsetMathXYArrow::targetMatrix() const -{ - return target_; -} - - -MathArray const & InsetMathXYArrow::targetCell() const -{ -#if 0 - InsetMathXYMatrix const * p = targetMatrix(); - int x = 0; - int y = 0; - MathArray const & t = cell(0); - for (MathArray::const_iterator it = t.begin(); it != t.end(); ++it) { - switch ((*it)->getChar()) { - case 'l': --x; break; - case 'r': ++x; break; - case 'u': --y; break; - case 'd': ++y; break; - } - } - //lyxerr << "target: x: " << x << " y: " << y << endl; - InsetMath::idx_type n = mi_.idx + p->ncols() * y + x; - if (n >= p->nargs()) { - lyxerr << "source: n: " << mi_.idx << "\n" - << "target: n: " << n << " out of range" << endl; - n = 0; - } - return p->cell(n); -#else - static MathArray dummy; - return dummy; -#endif -} - - -MathArray const & InsetMathXYArrow::sourceCell() const -{ -#if 0 - return targetMatrix()->cell(mi_.idx); -#else - static MathArray dummy; - return dummy; -#endif -} - - -bool InsetMathXYArrow::metrics(MetricsInfo & mi) const -{ - InsetMathNest::metrics(mi); - mi_ = mi; - FontSetChanger dummy(mi.base, "textrm"); -#if 0 - target_ = mi.inset ? mi.inset->asXYMatrixInset() : 0; - - if (editing()) { - int w = mathed_string_width(mi.base.font, from_ascii("target: ")); - width_ = w + max(cell(0).width(), cell(1).width()); - ascent_ = cell(0).ascent(); - descent_ = cell(0).descent() + cell(1).height() + 10; - } else { - width_ = 0; - ascent_ = 0; - descent_ = 0; - //mathed_string_dim(font_, "X", ascent_, descent_, width_); - } -#endif -} - - -void InsetMathXYArrow::draw(PainterInfo & pi, int x, int y) const -{ - metrics(mi_); - FontSetChanger dummy(pi.base, "textrm"); - - if (editing()) { - -#if 0 - - int lasc; - int ldes; - int lwid; - mathed_string_dim(pi.base.font, "target: ", lasc, ldes, lwid); - - cell(0).draw(pi, x + lwid, y); - pi.base.text(x + 3, y, "target"); - y += max(cell(0).descent(), ldes) + 5; - - y += max(cell(1).ascent(), lasc) + 5; - cell(1).draw(pi, x + lwid, y); - pi.base.text(x + 3, y, "label"); - -#endif - - } else { - - pi.pain.text(x, y, "X"); - MathArray const & s = sourceCell(); - MathArray const & t = targetCell(); - pi.pain.line(s.xm(), s.ym(), t.xm(), t.ym(), LColor::math); - cell(1).draw(pi, (s.xm() + t.xm())/2, (s.ym() + t.ym())/2); - - } -} - - -void InsetMathXYArrow::write(WriteStream & os) const -{ - os << "\\ar"; - if (cell(0).size()) - os << '[' << cell(0) << ']'; - if (cell(1).size()) - os << (up_ ? '^' : '_') << '{' << cell(1) << '}'; - os << " "; -} - - -void InsetMathXYArrow::normalize(NormalStream & os) const -{ - os << "[xyarrow "; - InsetMathNest::normalize(os); - os << ']'; -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathXYArrow.cpp b/src/mathed/InsetMathXYArrow.cpp new file mode 100644 index 0000000000..fb0f30252d --- /dev/null +++ b/src/mathed/InsetMathXYArrow.cpp @@ -0,0 +1,162 @@ +/** + * \file InsetMathXYArrow.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathXYArrow.h" +#include "MathStream.h" +#include "MathSupport.h" +#include "frontends/Painter.h" +#include "debug.h" + + +namespace lyx { + + +using std::max; + + +InsetMathXYArrow::InsetMathXYArrow() + : InsetMathNest(2) +{} + + +std::auto_ptr InsetMathXYArrow::clone() const +{ + return std::auto_ptr(new InsetMathXYArrow(*this)); +} + + +InsetMathXYMatrix const * InsetMathXYArrow::targetMatrix() const +{ + return target_; +} + + +MathArray const & InsetMathXYArrow::targetCell() const +{ +#if 0 + InsetMathXYMatrix const * p = targetMatrix(); + int x = 0; + int y = 0; + MathArray const & t = cell(0); + for (MathArray::const_iterator it = t.begin(); it != t.end(); ++it) { + switch ((*it)->getChar()) { + case 'l': --x; break; + case 'r': ++x; break; + case 'u': --y; break; + case 'd': ++y; break; + } + } + //lyxerr << "target: x: " << x << " y: " << y << endl; + InsetMath::idx_type n = mi_.idx + p->ncols() * y + x; + if (n >= p->nargs()) { + lyxerr << "source: n: " << mi_.idx << "\n" + << "target: n: " << n << " out of range" << endl; + n = 0; + } + return p->cell(n); +#else + static MathArray dummy; + return dummy; +#endif +} + + +MathArray const & InsetMathXYArrow::sourceCell() const +{ +#if 0 + return targetMatrix()->cell(mi_.idx); +#else + static MathArray dummy; + return dummy; +#endif +} + + +bool InsetMathXYArrow::metrics(MetricsInfo & mi) const +{ + InsetMathNest::metrics(mi); + mi_ = mi; + FontSetChanger dummy(mi.base, "textrm"); +#if 0 + target_ = mi.inset ? mi.inset->asXYMatrixInset() : 0; + + if (editing()) { + int w = mathed_string_width(mi.base.font, from_ascii("target: ")); + width_ = w + max(cell(0).width(), cell(1).width()); + ascent_ = cell(0).ascent(); + descent_ = cell(0).descent() + cell(1).height() + 10; + } else { + width_ = 0; + ascent_ = 0; + descent_ = 0; + //mathed_string_dim(font_, "X", ascent_, descent_, width_); + } +#endif +} + + +void InsetMathXYArrow::draw(PainterInfo & pi, int x, int y) const +{ + metrics(mi_); + FontSetChanger dummy(pi.base, "textrm"); + + if (editing()) { + +#if 0 + + int lasc; + int ldes; + int lwid; + mathed_string_dim(pi.base.font, "target: ", lasc, ldes, lwid); + + cell(0).draw(pi, x + lwid, y); + pi.base.text(x + 3, y, "target"); + y += max(cell(0).descent(), ldes) + 5; + + y += max(cell(1).ascent(), lasc) + 5; + cell(1).draw(pi, x + lwid, y); + pi.base.text(x + 3, y, "label"); + +#endif + + } else { + + pi.pain.text(x, y, "X"); + MathArray const & s = sourceCell(); + MathArray const & t = targetCell(); + pi.pain.line(s.xm(), s.ym(), t.xm(), t.ym(), LColor::math); + cell(1).draw(pi, (s.xm() + t.xm())/2, (s.ym() + t.ym())/2); + + } +} + + +void InsetMathXYArrow::write(WriteStream & os) const +{ + os << "\\ar"; + if (cell(0).size()) + os << '[' << cell(0) << ']'; + if (cell(1).size()) + os << (up_ ? '^' : '_') << '{' << cell(1) << '}'; + os << " "; +} + + +void InsetMathXYArrow::normalize(NormalStream & os) const +{ + os << "[xyarrow "; + InsetMathNest::normalize(os); + os << ']'; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathXYMatrix.C b/src/mathed/InsetMathXYMatrix.C deleted file mode 100644 index f8de6c7072..0000000000 --- a/src/mathed/InsetMathXYMatrix.C +++ /dev/null @@ -1,125 +0,0 @@ -/** - * \file InsetMathXYMatrix.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMathXYMatrix.h" -#include "MathStream.h" - -#include "LaTeXFeatures.h" -#include "support/std_ostream.h" - - -namespace lyx { - - -InsetMathXYMatrix::InsetMathXYMatrix(LyXLength const & s, char c) - : InsetMathGrid(1, 1), spacing_(s), spacing_code_(c) -{} - - -std::auto_ptr InsetMathXYMatrix::doClone() const -{ - return std::auto_ptr(new InsetMathXYMatrix(*this)); -} - - -int InsetMathXYMatrix::colsep() const -{ - return 40; -} - - -int InsetMathXYMatrix::rowsep() const -{ - return 40; -} - - -bool InsetMathXYMatrix::metrics(MetricsInfo & mi, Dimension & dim) const -{ - if (mi.base.style == LM_ST_DISPLAY) - mi.base.style = LM_ST_TEXT; - InsetMathGrid::metrics(mi, dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void InsetMathXYMatrix::write(WriteStream & os) const -{ - os << "\\xymatrix"; - switch (spacing_code_) { - case 'R': - case 'C': - case 'M': - case 'W': - case 'H': - case 'L': - os << '@' << spacing_code_ << '=' - << from_ascii(spacing_.asLatexString()); - break; - default: - if (!spacing_.empty()) - os << "@=" << from_ascii(spacing_.asLatexString()); - } - os << '{'; - InsetMathGrid::write(os); - os << "}\n"; -} - - -void InsetMathXYMatrix::infoize(odocstream & os) const -{ - os << "xymatrix "; - switch (spacing_code_) { - case 'R': - case 'C': - case 'M': - case 'W': - case 'H': - case 'L': - os << spacing_code_ << ' ' - << from_ascii(spacing_.asLatexString()) << ' '; - break; - default: - if (!spacing_.empty()) - os << from_ascii(spacing_.asLatexString()) << ' '; - } - InsetMathGrid::infoize(os); -} - - -void InsetMathXYMatrix::normalize(NormalStream & os) const -{ - os << "[xymatrix "; - InsetMathGrid::normalize(os); - os << ']'; -} - - -void InsetMathXYMatrix::maple(MapleStream & os) const -{ - os << "xymatrix("; - InsetMathGrid::maple(os); - os << ')'; -} - - -void InsetMathXYMatrix::validate(LaTeXFeatures & features) const -{ - features.require("xy"); - InsetMathGrid::validate(features); -} - - -} // namespace lyx diff --git a/src/mathed/InsetMathXYMatrix.cpp b/src/mathed/InsetMathXYMatrix.cpp new file mode 100644 index 0000000000..f8de6c7072 --- /dev/null +++ b/src/mathed/InsetMathXYMatrix.cpp @@ -0,0 +1,125 @@ +/** + * \file InsetMathXYMatrix.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathXYMatrix.h" +#include "MathStream.h" + +#include "LaTeXFeatures.h" +#include "support/std_ostream.h" + + +namespace lyx { + + +InsetMathXYMatrix::InsetMathXYMatrix(LyXLength const & s, char c) + : InsetMathGrid(1, 1), spacing_(s), spacing_code_(c) +{} + + +std::auto_ptr InsetMathXYMatrix::doClone() const +{ + return std::auto_ptr(new InsetMathXYMatrix(*this)); +} + + +int InsetMathXYMatrix::colsep() const +{ + return 40; +} + + +int InsetMathXYMatrix::rowsep() const +{ + return 40; +} + + +bool InsetMathXYMatrix::metrics(MetricsInfo & mi, Dimension & dim) const +{ + if (mi.base.style == LM_ST_DISPLAY) + mi.base.style = LM_ST_TEXT; + InsetMathGrid::metrics(mi, dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void InsetMathXYMatrix::write(WriteStream & os) const +{ + os << "\\xymatrix"; + switch (spacing_code_) { + case 'R': + case 'C': + case 'M': + case 'W': + case 'H': + case 'L': + os << '@' << spacing_code_ << '=' + << from_ascii(spacing_.asLatexString()); + break; + default: + if (!spacing_.empty()) + os << "@=" << from_ascii(spacing_.asLatexString()); + } + os << '{'; + InsetMathGrid::write(os); + os << "}\n"; +} + + +void InsetMathXYMatrix::infoize(odocstream & os) const +{ + os << "xymatrix "; + switch (spacing_code_) { + case 'R': + case 'C': + case 'M': + case 'W': + case 'H': + case 'L': + os << spacing_code_ << ' ' + << from_ascii(spacing_.asLatexString()) << ' '; + break; + default: + if (!spacing_.empty()) + os << from_ascii(spacing_.asLatexString()) << ' '; + } + InsetMathGrid::infoize(os); +} + + +void InsetMathXYMatrix::normalize(NormalStream & os) const +{ + os << "[xymatrix "; + InsetMathGrid::normalize(os); + os << ']'; +} + + +void InsetMathXYMatrix::maple(MapleStream & os) const +{ + os << "xymatrix("; + InsetMathGrid::maple(os); + os << ')'; +} + + +void InsetMathXYMatrix::validate(LaTeXFeatures & features) const +{ + features.require("xy"); + InsetMathGrid::validate(features); +} + + +} // namespace lyx diff --git a/src/mathed/MathAtom.C b/src/mathed/MathAtom.C deleted file mode 100644 index 87a569d821..0000000000 --- a/src/mathed/MathAtom.C +++ /dev/null @@ -1,56 +0,0 @@ -/** - * \file MathAtom.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "MathAtom.h" -#include "InsetMath.h" - - -namespace lyx { - -using std::swap; - - -MathAtom::MathAtom() - : nucleus_(0) -{} - - -MathAtom::MathAtom(InsetBase * p) - : nucleus_(static_cast(p)) -{} - - -MathAtom::MathAtom(MathAtom const & at) - : nucleus_(0) -{ - if (at.nucleus_) - nucleus_ = static_cast(at.nucleus_->clone().release()); -} - - -MathAtom & MathAtom::operator=(MathAtom const & at) -{ - if (&at == this) - return *this; - MathAtom tmp(at); - swap(tmp.nucleus_, nucleus_); - return *this; -} - - -MathAtom::~MathAtom() -{ - delete nucleus_; -} - - -} // namespace lyx diff --git a/src/mathed/MathAtom.cpp b/src/mathed/MathAtom.cpp new file mode 100644 index 0000000000..87a569d821 --- /dev/null +++ b/src/mathed/MathAtom.cpp @@ -0,0 +1,56 @@ +/** + * \file MathAtom.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "MathAtom.h" +#include "InsetMath.h" + + +namespace lyx { + +using std::swap; + + +MathAtom::MathAtom() + : nucleus_(0) +{} + + +MathAtom::MathAtom(InsetBase * p) + : nucleus_(static_cast(p)) +{} + + +MathAtom::MathAtom(MathAtom const & at) + : nucleus_(0) +{ + if (at.nucleus_) + nucleus_ = static_cast(at.nucleus_->clone().release()); +} + + +MathAtom & MathAtom::operator=(MathAtom const & at) +{ + if (&at == this) + return *this; + MathAtom tmp(at); + swap(tmp.nucleus_, nucleus_); + return *this; +} + + +MathAtom::~MathAtom() +{ + delete nucleus_; +} + + +} // namespace lyx diff --git a/src/mathed/MathAutoCorrect.C b/src/mathed/MathAutoCorrect.C deleted file mode 100644 index c275a9341f..0000000000 --- a/src/mathed/MathAutoCorrect.C +++ /dev/null @@ -1,189 +0,0 @@ -/** - * \file MathAutoCorrect.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "MathAutoCorrect.h" -#include "MathData.h" -#include "InsetMath.h" -#include "MathSupport.h" -#include "MathParser.h" -#include "debug.h" - -#include "support/filetools.h" // LibFileSearch - -#include -#include - - -namespace lyx { - -using support::libFileSearch; - -using std::string; -using std::ifstream; -using std::endl; -using std::vector; - -namespace { - -class Correction { -public: - /// - Correction() {} - /// - bool correct(MathAtom & at, char_type c) const; - /// - bool read(idocstream & is); - /// - void write(odocstream & os) const; -private: - /// - MathAtom from1_; - /// - char_type from2_; - /// - MathAtom to_; -}; - - -bool Correction::read(idocstream & is) -{ - docstring s1, s2, s3; - is >> s1 >> s2 >> s3; - if (!is) - return false; - if (s2.size() != 1) - return false; - MathArray ar1, ar3; - mathed_parse_cell(ar1, s1); - mathed_parse_cell(ar3, s3); - if (ar1.size() != 1 || ar3.size() != 1) - return false; - from1_ = ar1.front(); - from2_ = s2[0]; - to_ = ar3.front(); - return true; -} - - -void Correction::write(odocstream & os) const -{ - os << "from: '" << from1_ << "' and '" << from2_ - << "' to '" << to_ << '\'' << endl; -} - - -bool Correction::correct(MathAtom & at, char_type c) const -{ - //LYXERR(Debug::MATHED) - // << "trying to correct ar: " << at << " from: '" << from1_ << '\'' << endl; - if (from2_ != c) - return false; - if (asString(at) != asString(from1_)) - return false; - LYXERR(Debug::MATHED) - << "match found! subst in " << at - << " from: '" << from1_ << "' to '" << to_ << '\'' << endl; - at = to_; - return true; -} - - -idocstream & operator>>(idocstream & is, Correction & corr) -{ - corr.read(is); - return is; -} - - -odocstream & operator<<(odocstream & os, Correction & corr) -{ - corr.write(os); - return os; -} - - - - -class Corrections { -public: - /// - typedef vector::const_iterator const_iterator; - /// - Corrections() {} - /// - void insert(const Correction & corr) { data_.push_back(corr); } - /// - bool correct(MathAtom & at, char_type c) const; -private: - /// - vector data_; -}; - - -bool Corrections::correct(MathAtom & at, char_type c) const -{ - for (const_iterator it = data_.begin(); it != data_.end(); ++it) - if (it->correct(at, c)) - return true; - return false; -} - - -Corrections theCorrections; - -void initAutoCorrect() -{ - LYXERR(Debug::MATHED) << "reading autocorrect file" << endl; - support::FileName const file = libFileSearch(string(), "autocorrect"); - if (file.empty()) { - lyxerr << "Could not find autocorrect file" << endl; - return; - } - - string line; - ifstream is(file.toFilesystemEncoding().c_str()); - while (getline(is, line)) { - if (line.size() == 0 || line[0] == '#') { - //LYXERR(Debug::MATHED) << "ignoring line '" << line << '\'' << endl; - continue; - } - idocstringstream il(from_utf8(line)); - - //LYXERR(Debug::MATHED) << "line '" << line << '\'' << endl; - Correction corr; - if (corr.read(il)) { - //LYXERR(Debug::MATHED) << "parsed: '" << corr << '\'' << endl; - theCorrections.insert(corr); - } - } - - LYXERR(Debug::MATHED) << "done reading autocorrections." << endl; -} - - -} // namespace anon - - -bool math_autocorrect(MathAtom & at, char c) -{ - static bool initialized = false; - - if (!initialized) { - initAutoCorrect(); - initialized = true; - } - - return theCorrections.correct(at, c); -} - - -} // namespace lyx diff --git a/src/mathed/MathAutoCorrect.cpp b/src/mathed/MathAutoCorrect.cpp new file mode 100644 index 0000000000..c275a9341f --- /dev/null +++ b/src/mathed/MathAutoCorrect.cpp @@ -0,0 +1,189 @@ +/** + * \file MathAutoCorrect.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "MathAutoCorrect.h" +#include "MathData.h" +#include "InsetMath.h" +#include "MathSupport.h" +#include "MathParser.h" +#include "debug.h" + +#include "support/filetools.h" // LibFileSearch + +#include +#include + + +namespace lyx { + +using support::libFileSearch; + +using std::string; +using std::ifstream; +using std::endl; +using std::vector; + +namespace { + +class Correction { +public: + /// + Correction() {} + /// + bool correct(MathAtom & at, char_type c) const; + /// + bool read(idocstream & is); + /// + void write(odocstream & os) const; +private: + /// + MathAtom from1_; + /// + char_type from2_; + /// + MathAtom to_; +}; + + +bool Correction::read(idocstream & is) +{ + docstring s1, s2, s3; + is >> s1 >> s2 >> s3; + if (!is) + return false; + if (s2.size() != 1) + return false; + MathArray ar1, ar3; + mathed_parse_cell(ar1, s1); + mathed_parse_cell(ar3, s3); + if (ar1.size() != 1 || ar3.size() != 1) + return false; + from1_ = ar1.front(); + from2_ = s2[0]; + to_ = ar3.front(); + return true; +} + + +void Correction::write(odocstream & os) const +{ + os << "from: '" << from1_ << "' and '" << from2_ + << "' to '" << to_ << '\'' << endl; +} + + +bool Correction::correct(MathAtom & at, char_type c) const +{ + //LYXERR(Debug::MATHED) + // << "trying to correct ar: " << at << " from: '" << from1_ << '\'' << endl; + if (from2_ != c) + return false; + if (asString(at) != asString(from1_)) + return false; + LYXERR(Debug::MATHED) + << "match found! subst in " << at + << " from: '" << from1_ << "' to '" << to_ << '\'' << endl; + at = to_; + return true; +} + + +idocstream & operator>>(idocstream & is, Correction & corr) +{ + corr.read(is); + return is; +} + + +odocstream & operator<<(odocstream & os, Correction & corr) +{ + corr.write(os); + return os; +} + + + + +class Corrections { +public: + /// + typedef vector::const_iterator const_iterator; + /// + Corrections() {} + /// + void insert(const Correction & corr) { data_.push_back(corr); } + /// + bool correct(MathAtom & at, char_type c) const; +private: + /// + vector data_; +}; + + +bool Corrections::correct(MathAtom & at, char_type c) const +{ + for (const_iterator it = data_.begin(); it != data_.end(); ++it) + if (it->correct(at, c)) + return true; + return false; +} + + +Corrections theCorrections; + +void initAutoCorrect() +{ + LYXERR(Debug::MATHED) << "reading autocorrect file" << endl; + support::FileName const file = libFileSearch(string(), "autocorrect"); + if (file.empty()) { + lyxerr << "Could not find autocorrect file" << endl; + return; + } + + string line; + ifstream is(file.toFilesystemEncoding().c_str()); + while (getline(is, line)) { + if (line.size() == 0 || line[0] == '#') { + //LYXERR(Debug::MATHED) << "ignoring line '" << line << '\'' << endl; + continue; + } + idocstringstream il(from_utf8(line)); + + //LYXERR(Debug::MATHED) << "line '" << line << '\'' << endl; + Correction corr; + if (corr.read(il)) { + //LYXERR(Debug::MATHED) << "parsed: '" << corr << '\'' << endl; + theCorrections.insert(corr); + } + } + + LYXERR(Debug::MATHED) << "done reading autocorrections." << endl; +} + + +} // namespace anon + + +bool math_autocorrect(MathAtom & at, char c) +{ + static bool initialized = false; + + if (!initialized) { + initAutoCorrect(); + initialized = true; + } + + return theCorrections.correct(at, c); +} + + +} // namespace lyx diff --git a/src/mathed/MathData.C b/src/mathed/MathData.C deleted file mode 100644 index b0639032ff..0000000000 --- a/src/mathed/MathData.C +++ /dev/null @@ -1,485 +0,0 @@ -/** - * \file MathData.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "MathData.h" -#include "InsetMathFont.h" -#include "InsetMathScript.h" -#include "InsetMathMacro.h" -#include "MathMacroTable.h" -#include "MathStream.h" -#include "MathSupport.h" -#include "MathReplace.h" - -#include "BufferView.h" -#include "buffer.h" -#include "cursor.h" -#include "debug.h" -#include "LColor.h" - -#include "frontends/FontMetrics.h" -#include "frontends/Painter.h" - -#include - - -namespace lyx { - -using std::abs; -using std::endl; -using std::min; -using std::ostringstream; -using std::string; -using std::vector; - - -MathArray::MathArray(const_iterator from, const_iterator to) - : base_type(from, to) -{} - - -MathAtom & MathArray::operator[](pos_type pos) -{ - BOOST_ASSERT(pos < size()); - return base_type::operator[](pos); -} - - -MathAtom const & MathArray::operator[](pos_type pos) const -{ - BOOST_ASSERT(pos < size()); - return base_type::operator[](pos); -} - - -void MathArray::insert(size_type pos, MathAtom const & t) -{ - base_type::insert(begin() + pos, t); -} - - -void MathArray::insert(size_type pos, MathArray const & ar) -{ - BOOST_ASSERT(pos <= size()); - base_type::insert(begin() + pos, ar.begin(), ar.end()); -} - - -void MathArray::append(MathArray const & ar) -{ - insert(size(), ar); -} - - -void MathArray::erase(size_type pos) -{ - if (pos < size()) - erase(pos, pos + 1); -} - - -void MathArray::erase(iterator pos1, iterator pos2) -{ - base_type::erase(pos1, pos2); -} - - -void MathArray::erase(iterator pos) -{ - base_type::erase(pos); -} - - -void MathArray::erase(size_type pos1, size_type pos2) -{ - base_type::erase(begin() + pos1, begin() + pos2); -} - - -void MathArray::dump2() const -{ - odocstringstream os; - NormalStream ns(os); - for (const_iterator it = begin(); it != end(); ++it) - ns << *it << ' '; - lyxerr << to_utf8(os.str()); -} - - -void MathArray::dump() const -{ - odocstringstream os; - NormalStream ns(os); - for (const_iterator it = begin(); it != end(); ++it) - ns << '<' << *it << '>'; - lyxerr << to_utf8(os.str()); -} - - -void MathArray::validate(LaTeXFeatures & features) const -{ - for (const_iterator it = begin(); it != end(); ++it) - (*it)->validate(features); -} - - -bool MathArray::match(MathArray const & ar) const -{ - return size() == ar.size() && matchpart(ar, 0); -} - - -bool MathArray::matchpart(MathArray const & ar, pos_type pos) const -{ - if (size() < ar.size() + pos) - return false; - const_iterator it = begin() + pos; - for (const_iterator jt = ar.begin(); jt != ar.end(); ++jt, ++it) - if (asString(*it) != asString(*jt)) - return false; - return true; -} - - -void MathArray::replace(ReplaceData & rep) -{ - for (size_type i = 0; i < size(); ++i) { - if (find1(rep.from, i)) { - // match found - lyxerr << "match found!" << endl; - erase(i, i + rep.from.size()); - insert(i, rep.to); - } - } - -#ifdef WITH_WARNINGS -#warning temporarily disabled - // for (const_iterator it = begin(); it != end(); ++it) - // it->nucleus()->replace(rep); -#endif -} - - -bool MathArray::find1(MathArray const & ar, size_type pos) const -{ - lyxerr << "finding '" << ar << "' in '" << *this << "'" << endl; - for (size_type i = 0, n = ar.size(); i < n; ++i) - if (asString(operator[](pos + i)) != asString(ar[i])) - return false; - return true; -} - - -MathArray::size_type MathArray::find(MathArray const & ar) const -{ - for (int i = 0, last = size() - ar.size(); i < last; ++i) - if (find1(ar, i)) - return i; - return size(); -} - - -MathArray::size_type MathArray::find_last(MathArray const & ar) const -{ - for (int i = size() - ar.size(); i >= 0; --i) - if (find1(ar, i)) - return i; - return size(); -} - - -bool MathArray::contains(MathArray const & ar) const -{ - if (find(ar) != size()) - return true; - for (const_iterator it = begin(); it != end(); ++it) - if ((*it)->contains(ar)) - return true; - return false; -} - - -void MathArray::touch() const -{ -} - - -bool MathArray::metrics(MetricsInfo & mi, Dimension & dim) const -{ - dim = dim_; - metrics(mi); - if (dim_ == dim) - return false; - dim = dim_; - return true; -} - - -namespace { - -bool isInside(DocIterator const & it, MathArray const & ar, - pos_type p1, pos_type p2) -{ - for (size_t i = 0; i != it.depth(); ++i) { - CursorSlice const & sl = it[i]; - if (sl.inset().inMathed() && &sl.cell() == &ar) - return p1 <= sl.pos() && sl.pos() < p2; - } - return false; -} - -} - - - -void MathArray::metrics(MetricsInfo & mi) const -{ - frontend::FontMetrics const & fm = theFontMetrics(mi.base.font); - dim_ = fm.dimension('I'); - int xascent = fm.dimension('x').ascent(); - if (xascent >= dim_.asc) - xascent = (2 * dim_.asc) / 3; - minasc_ = xascent; - mindes_ = (3 * xascent) / 4; - slevel_ = (4 * xascent) / 5; - sshift_ = xascent / 4; - kerning_ = 0; - - if (empty()) - return; - - dim_.asc = 0; - dim_.wid = 0; - Dimension d; - //BufferView & bv = *mi.base.bv; - //Buffer const & buf = *bv.buffer(); - for (size_t i = 0, n = size(); i != n; ++i) { - MathAtom const & at = operator[](i); -#if 0 - MathMacro const * mac = at->asMacro(); - if (mac && buf.hasMacro(mac->name())) { - MacroData const & tmpl = buf.getMacro(mac->name()); - int numargs = tmpl.numargs(); - if (i + numargs > n) - numargs = n - i - 1; - lyxerr << "metrics:found macro: " << mac->name() - << " numargs: " << numargs << endl; - if (!isInside(bv.cursor(), *this, i + 1, i + numargs + 1)) { - MathArray args(begin() + i + 1, begin() + i + numargs + 1); - MathArray exp; - tmpl.expand(args, exp); - mac->setExpansion(exp, args); - mac->metricsExpanded(mi, d); - dim_.wid += mac->widthExpanded(); - i += numargs; - continue; - } - } -#endif - at->metrics(mi, d); - dim_ += d; - if (i == n - 1) - kerning_ = at->kerning(); - } -} - - -void MathArray::draw(PainterInfo & pi, int x, int y) const -{ - //lyxerr << "MathArray::draw: x: " << x << " y: " << y << endl; - BufferView & bv = *pi.base.bv; - setXY(bv, x, y); - - if (empty()) { - pi.pain.rectangle(x, y - ascent(), width(), height(), LColor::mathline); - return; - } - - // don't draw outside the workarea - if (y + descent() <= 0 - || y - ascent() >= bv.workHeight() - || x + width() <= 0 - || x >= bv. workWidth()) - return; - - for (size_t i = 0, n = size(); i != n; ++i) { - MathAtom const & at = operator[](i); -#if 0 - Buffer const & buf = bv.buffer(); - // special macro handling - MathMacro const * mac = at->asMacro(); - if (mac && buf.hasMacro(mac->name())) { - MacroData const & tmpl = buf.getMacro(mac->name()); - int numargs = tmpl.numargs(); - if (i + numargs > n) - numargs = n - i - 1; - if (!isInside(bv.cursor(), *this, i + 1, i + numargs + 1)) { - mac->drawExpanded(pi, x, y); - x += mac->widthExpanded(); - i += numargs; - continue; - } - } -#endif - bv.coordCache().insets().add(at.nucleus(), x, y); - at->drawSelection(pi, x, y); - at->draw(pi, x, y); - x += at->width(); - } -} - - -void MathArray::metricsT(TextMetricsInfo const & mi, Dimension & dim) const -{ - dim.clear(); - Dimension d; - for (const_iterator it = begin(); it != end(); ++it) { - (*it)->metricsT(mi, d); - dim += d; - } -} - - -void MathArray::drawT(TextPainter & pain, int x, int y) const -{ - //lyxerr << "x: " << x << " y: " << y << ' ' << pain.workAreaHeight() << endl; - - // FIXME: Abdel 16/10/2006 - // This drawT() method is never used, this is dead code. - - for (const_iterator it = begin(), et = end(); it != et; ++it) { - (*it)->drawT(pain, x, y); - //x += (*it)->width_; - x += 2; - } -} - - -int MathArray::pos2x(size_type pos) const -{ - return pos2x(pos, 0); -} - - -int MathArray::pos2x(size_type pos, int glue) const -{ - int x = 0; - size_type target = min(pos, size()); - for (size_type i = 0; i < target; ++i) { - const_iterator it = begin() + i; - if ((*it)->getChar() == ' ') - x += glue; - //lyxerr << "char: " << (*it)->getChar() - // << "width: " << (*it)->width() << std::endl; - x += (*it)->width(); - } - return x; -} - - -MathArray::size_type MathArray::x2pos(int targetx) const -{ - return x2pos(targetx, 0); -} - - -MathArray::size_type MathArray::x2pos(int targetx, int glue) const -{ - const_iterator it = begin(); - int lastx = 0; - int currx = 0; - // find first position after targetx - for (; currx < targetx && it < end(); ++it) { - lastx = currx; - if ((*it)->getChar() == ' ') - currx += glue; - currx += (*it)->width(); - } - - /** - * If we are not at the beginning of the array, go to the left - * of the inset if one of the following two condition holds: - * - the current inset is editable (so that the cursor tip is - * deeper than us): in this case, we want all intermediate - * cursor slices to be before insets; - * - the mouse is closer to the left side of the inset than to - * the right one. - * See bug 1918 for details. - **/ - if (it != begin() && currx >= targetx - && ((*boost::prior(it))->asNestInset() - || abs(lastx - targetx) < abs(currx - targetx))) { - --it; - } - - return it - begin(); -} - - -int MathArray::dist(BufferView const & bv, int x, int y) const -{ - int xx = 0; - int yy = 0; - - const int xo_ = xo(bv); - const int yo_ = yo(bv); - - if (x < xo_) - xx = xo_ - x; - else if (x > xo_ + width()) - xx = x - xo_ - width(); - - if (y < yo_ - ascent()) - yy = yo_ - ascent() - y; - else if (y > yo_ + descent()) - yy = y - yo_ - descent(); - - return xx + yy; -} - - -void MathArray::setXY(BufferView & bv, int x, int y) const -{ - //lyxerr << "setting position cache for MathArray " << this << std::endl; - bv.coordCache().arrays().add(this, x, y); -} - - -int MathArray::xo(BufferView const & bv) const -{ - return bv.coordCache().getArrays().x(this); -} - - -int MathArray::yo(BufferView const & bv) const -{ - return bv.coordCache().getArrays().y(this); -} - - -std::ostream & operator<<(std::ostream & os, MathArray const & ar) -{ - odocstringstream oss; - NormalStream ns(oss); - ns << ar; - return os << to_utf8(oss.str()); -} - - -odocstream & operator<<(odocstream & os, MathArray const & ar) -{ - NormalStream ns(os); - ns << ar; - return os; -} - - -} // namespace lyx diff --git a/src/mathed/MathData.cpp b/src/mathed/MathData.cpp new file mode 100644 index 0000000000..b0639032ff --- /dev/null +++ b/src/mathed/MathData.cpp @@ -0,0 +1,485 @@ +/** + * \file MathData.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "MathData.h" +#include "InsetMathFont.h" +#include "InsetMathScript.h" +#include "InsetMathMacro.h" +#include "MathMacroTable.h" +#include "MathStream.h" +#include "MathSupport.h" +#include "MathReplace.h" + +#include "BufferView.h" +#include "buffer.h" +#include "cursor.h" +#include "debug.h" +#include "LColor.h" + +#include "frontends/FontMetrics.h" +#include "frontends/Painter.h" + +#include + + +namespace lyx { + +using std::abs; +using std::endl; +using std::min; +using std::ostringstream; +using std::string; +using std::vector; + + +MathArray::MathArray(const_iterator from, const_iterator to) + : base_type(from, to) +{} + + +MathAtom & MathArray::operator[](pos_type pos) +{ + BOOST_ASSERT(pos < size()); + return base_type::operator[](pos); +} + + +MathAtom const & MathArray::operator[](pos_type pos) const +{ + BOOST_ASSERT(pos < size()); + return base_type::operator[](pos); +} + + +void MathArray::insert(size_type pos, MathAtom const & t) +{ + base_type::insert(begin() + pos, t); +} + + +void MathArray::insert(size_type pos, MathArray const & ar) +{ + BOOST_ASSERT(pos <= size()); + base_type::insert(begin() + pos, ar.begin(), ar.end()); +} + + +void MathArray::append(MathArray const & ar) +{ + insert(size(), ar); +} + + +void MathArray::erase(size_type pos) +{ + if (pos < size()) + erase(pos, pos + 1); +} + + +void MathArray::erase(iterator pos1, iterator pos2) +{ + base_type::erase(pos1, pos2); +} + + +void MathArray::erase(iterator pos) +{ + base_type::erase(pos); +} + + +void MathArray::erase(size_type pos1, size_type pos2) +{ + base_type::erase(begin() + pos1, begin() + pos2); +} + + +void MathArray::dump2() const +{ + odocstringstream os; + NormalStream ns(os); + for (const_iterator it = begin(); it != end(); ++it) + ns << *it << ' '; + lyxerr << to_utf8(os.str()); +} + + +void MathArray::dump() const +{ + odocstringstream os; + NormalStream ns(os); + for (const_iterator it = begin(); it != end(); ++it) + ns << '<' << *it << '>'; + lyxerr << to_utf8(os.str()); +} + + +void MathArray::validate(LaTeXFeatures & features) const +{ + for (const_iterator it = begin(); it != end(); ++it) + (*it)->validate(features); +} + + +bool MathArray::match(MathArray const & ar) const +{ + return size() == ar.size() && matchpart(ar, 0); +} + + +bool MathArray::matchpart(MathArray const & ar, pos_type pos) const +{ + if (size() < ar.size() + pos) + return false; + const_iterator it = begin() + pos; + for (const_iterator jt = ar.begin(); jt != ar.end(); ++jt, ++it) + if (asString(*it) != asString(*jt)) + return false; + return true; +} + + +void MathArray::replace(ReplaceData & rep) +{ + for (size_type i = 0; i < size(); ++i) { + if (find1(rep.from, i)) { + // match found + lyxerr << "match found!" << endl; + erase(i, i + rep.from.size()); + insert(i, rep.to); + } + } + +#ifdef WITH_WARNINGS +#warning temporarily disabled + // for (const_iterator it = begin(); it != end(); ++it) + // it->nucleus()->replace(rep); +#endif +} + + +bool MathArray::find1(MathArray const & ar, size_type pos) const +{ + lyxerr << "finding '" << ar << "' in '" << *this << "'" << endl; + for (size_type i = 0, n = ar.size(); i < n; ++i) + if (asString(operator[](pos + i)) != asString(ar[i])) + return false; + return true; +} + + +MathArray::size_type MathArray::find(MathArray const & ar) const +{ + for (int i = 0, last = size() - ar.size(); i < last; ++i) + if (find1(ar, i)) + return i; + return size(); +} + + +MathArray::size_type MathArray::find_last(MathArray const & ar) const +{ + for (int i = size() - ar.size(); i >= 0; --i) + if (find1(ar, i)) + return i; + return size(); +} + + +bool MathArray::contains(MathArray const & ar) const +{ + if (find(ar) != size()) + return true; + for (const_iterator it = begin(); it != end(); ++it) + if ((*it)->contains(ar)) + return true; + return false; +} + + +void MathArray::touch() const +{ +} + + +bool MathArray::metrics(MetricsInfo & mi, Dimension & dim) const +{ + dim = dim_; + metrics(mi); + if (dim_ == dim) + return false; + dim = dim_; + return true; +} + + +namespace { + +bool isInside(DocIterator const & it, MathArray const & ar, + pos_type p1, pos_type p2) +{ + for (size_t i = 0; i != it.depth(); ++i) { + CursorSlice const & sl = it[i]; + if (sl.inset().inMathed() && &sl.cell() == &ar) + return p1 <= sl.pos() && sl.pos() < p2; + } + return false; +} + +} + + + +void MathArray::metrics(MetricsInfo & mi) const +{ + frontend::FontMetrics const & fm = theFontMetrics(mi.base.font); + dim_ = fm.dimension('I'); + int xascent = fm.dimension('x').ascent(); + if (xascent >= dim_.asc) + xascent = (2 * dim_.asc) / 3; + minasc_ = xascent; + mindes_ = (3 * xascent) / 4; + slevel_ = (4 * xascent) / 5; + sshift_ = xascent / 4; + kerning_ = 0; + + if (empty()) + return; + + dim_.asc = 0; + dim_.wid = 0; + Dimension d; + //BufferView & bv = *mi.base.bv; + //Buffer const & buf = *bv.buffer(); + for (size_t i = 0, n = size(); i != n; ++i) { + MathAtom const & at = operator[](i); +#if 0 + MathMacro const * mac = at->asMacro(); + if (mac && buf.hasMacro(mac->name())) { + MacroData const & tmpl = buf.getMacro(mac->name()); + int numargs = tmpl.numargs(); + if (i + numargs > n) + numargs = n - i - 1; + lyxerr << "metrics:found macro: " << mac->name() + << " numargs: " << numargs << endl; + if (!isInside(bv.cursor(), *this, i + 1, i + numargs + 1)) { + MathArray args(begin() + i + 1, begin() + i + numargs + 1); + MathArray exp; + tmpl.expand(args, exp); + mac->setExpansion(exp, args); + mac->metricsExpanded(mi, d); + dim_.wid += mac->widthExpanded(); + i += numargs; + continue; + } + } +#endif + at->metrics(mi, d); + dim_ += d; + if (i == n - 1) + kerning_ = at->kerning(); + } +} + + +void MathArray::draw(PainterInfo & pi, int x, int y) const +{ + //lyxerr << "MathArray::draw: x: " << x << " y: " << y << endl; + BufferView & bv = *pi.base.bv; + setXY(bv, x, y); + + if (empty()) { + pi.pain.rectangle(x, y - ascent(), width(), height(), LColor::mathline); + return; + } + + // don't draw outside the workarea + if (y + descent() <= 0 + || y - ascent() >= bv.workHeight() + || x + width() <= 0 + || x >= bv. workWidth()) + return; + + for (size_t i = 0, n = size(); i != n; ++i) { + MathAtom const & at = operator[](i); +#if 0 + Buffer const & buf = bv.buffer(); + // special macro handling + MathMacro const * mac = at->asMacro(); + if (mac && buf.hasMacro(mac->name())) { + MacroData const & tmpl = buf.getMacro(mac->name()); + int numargs = tmpl.numargs(); + if (i + numargs > n) + numargs = n - i - 1; + if (!isInside(bv.cursor(), *this, i + 1, i + numargs + 1)) { + mac->drawExpanded(pi, x, y); + x += mac->widthExpanded(); + i += numargs; + continue; + } + } +#endif + bv.coordCache().insets().add(at.nucleus(), x, y); + at->drawSelection(pi, x, y); + at->draw(pi, x, y); + x += at->width(); + } +} + + +void MathArray::metricsT(TextMetricsInfo const & mi, Dimension & dim) const +{ + dim.clear(); + Dimension d; + for (const_iterator it = begin(); it != end(); ++it) { + (*it)->metricsT(mi, d); + dim += d; + } +} + + +void MathArray::drawT(TextPainter & pain, int x, int y) const +{ + //lyxerr << "x: " << x << " y: " << y << ' ' << pain.workAreaHeight() << endl; + + // FIXME: Abdel 16/10/2006 + // This drawT() method is never used, this is dead code. + + for (const_iterator it = begin(), et = end(); it != et; ++it) { + (*it)->drawT(pain, x, y); + //x += (*it)->width_; + x += 2; + } +} + + +int MathArray::pos2x(size_type pos) const +{ + return pos2x(pos, 0); +} + + +int MathArray::pos2x(size_type pos, int glue) const +{ + int x = 0; + size_type target = min(pos, size()); + for (size_type i = 0; i < target; ++i) { + const_iterator it = begin() + i; + if ((*it)->getChar() == ' ') + x += glue; + //lyxerr << "char: " << (*it)->getChar() + // << "width: " << (*it)->width() << std::endl; + x += (*it)->width(); + } + return x; +} + + +MathArray::size_type MathArray::x2pos(int targetx) const +{ + return x2pos(targetx, 0); +} + + +MathArray::size_type MathArray::x2pos(int targetx, int glue) const +{ + const_iterator it = begin(); + int lastx = 0; + int currx = 0; + // find first position after targetx + for (; currx < targetx && it < end(); ++it) { + lastx = currx; + if ((*it)->getChar() == ' ') + currx += glue; + currx += (*it)->width(); + } + + /** + * If we are not at the beginning of the array, go to the left + * of the inset if one of the following two condition holds: + * - the current inset is editable (so that the cursor tip is + * deeper than us): in this case, we want all intermediate + * cursor slices to be before insets; + * - the mouse is closer to the left side of the inset than to + * the right one. + * See bug 1918 for details. + **/ + if (it != begin() && currx >= targetx + && ((*boost::prior(it))->asNestInset() + || abs(lastx - targetx) < abs(currx - targetx))) { + --it; + } + + return it - begin(); +} + + +int MathArray::dist(BufferView const & bv, int x, int y) const +{ + int xx = 0; + int yy = 0; + + const int xo_ = xo(bv); + const int yo_ = yo(bv); + + if (x < xo_) + xx = xo_ - x; + else if (x > xo_ + width()) + xx = x - xo_ - width(); + + if (y < yo_ - ascent()) + yy = yo_ - ascent() - y; + else if (y > yo_ + descent()) + yy = y - yo_ - descent(); + + return xx + yy; +} + + +void MathArray::setXY(BufferView & bv, int x, int y) const +{ + //lyxerr << "setting position cache for MathArray " << this << std::endl; + bv.coordCache().arrays().add(this, x, y); +} + + +int MathArray::xo(BufferView const & bv) const +{ + return bv.coordCache().getArrays().x(this); +} + + +int MathArray::yo(BufferView const & bv) const +{ + return bv.coordCache().getArrays().y(this); +} + + +std::ostream & operator<<(std::ostream & os, MathArray const & ar) +{ + odocstringstream oss; + NormalStream ns(oss); + ns << ar; + return os << to_utf8(oss.str()); +} + + +odocstream & operator<<(odocstream & os, MathArray const & ar) +{ + NormalStream ns(os); + ns << ar; + return os; +} + + +} // namespace lyx diff --git a/src/mathed/MathExtern.C b/src/mathed/MathExtern.C deleted file mode 100644 index 36ca80104e..0000000000 --- a/src/mathed/MathExtern.C +++ /dev/null @@ -1,1452 +0,0 @@ -/** - * \file MathExtern.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -// This file contains most of the magic that extracts "context -// information" from the unstructered layout-oriented stuff in an -// MathArray. - -#include - -#include "MathExtern.h" -#include "InsetMathArray.h" -#include "InsetMathChar.h" -#include "InsetMathDelim.h" -#include "MathData.h" -#include "InsetMathDiff.h" -#include "InsetMathExFunc.h" -#include "InsetMathExInt.h" -#include "InsetMathFont.h" -#include "InsetMathFrac.h" -#include "InsetMathLim.h" -#include "InsetMathMatrix.h" -#include "MathStream.h" -#include "InsetMathNumber.h" -#include "InsetMathScript.h" -#include "InsetMathString.h" -#include "InsetMathSymbol.h" -#include "MathParser.h" -#include "debug.h" -#include "support/filetools.h" -#include "support/lstrings.h" -#include "support/lyxlib.h" -#include "frontends/controllers/ControlMath.h" - -#include -#include -#include - - -namespace lyx { - -using support::cmd_ret; -using support::getVectorFromString; -using support::libFileSearch; -using support::runCommand; -using support::FileName; -using support::quoteName; -using support::tempName; -using support::unlink; -using support::subst; - -using frontend::function_names; - -using std::endl; -using std::find_if; -using std::auto_ptr; -using std::istringstream; -using std::ostream; -using std::swap; -using std::string; -using std::vector; - -static size_t const npos = lyx::docstring::npos; - -// define a function for tests -typedef bool TestItemFunc(MathAtom const &); - -// define a function for replacing subexpressions -typedef MathAtom ReplaceArgumentFunc(const MathArray & ar); - - - -// try to extract a super/subscript -// modify iterator position to point behind the thing -bool extractScript(MathArray & ar, - MathArray::iterator & pos, MathArray::iterator last, bool superscript) -{ - // nothing to get here - if (pos == last) - return false; - - // is this a scriptinset? - if (!(*pos)->asScriptInset()) - return false; - - // do we want superscripts only? - if (superscript && !(*pos)->asScriptInset()->hasUp()) - return false; - - // it is a scriptinset, use it. - ar.push_back(*pos); - ++pos; - return true; -} - - -// try to extract an "argument" to some function. -// returns position behind the argument -MathArray::iterator extractArgument(MathArray & ar, - MathArray::iterator pos, MathArray::iterator last, bool function = false) -{ - // nothing to get here - if (pos == last) - return pos; - - // something delimited _is_ an argument - if ((*pos)->asDelimInset()) { - // leave out delimiters if this is a function argument - if (function) { - MathArray const & arg = (*pos)->asDelimInset()->cell(0); - MathArray::const_iterator cur = arg.begin(); - MathArray::const_iterator end = arg.end(); - while (cur != end) - ar.push_back(*cur++); - } else - ar.push_back(*pos); - ++pos; - if (pos == last) - return pos; - // if there's one, get following superscript only if this - // isn't a function argument - if (!function) - extractScript(ar, pos, last, true); - return pos; - } - - // always take the first thing, no matter what it is - ar.push_back(*pos); - - // go ahead if possible - ++pos; - if (pos == last) - return pos; - - // if the next item is a super/subscript, it most certainly belongs - // to the thing we have - extractScript(ar, pos, last, false); - if (pos == last) - return pos; - - // but it might be more than that. - // FIXME: not implemented - //for (MathArray::iterator it = pos + 1; it != last; ++it) { - // // always take the first thing, no matter - // if (it == pos) { - // ar.push_back(*it); - // continue; - // } - //} - return pos; -} - - -// returns sequence of char with same code starting at it up to end -// it might be less, though... -docstring charSequence - (MathArray::const_iterator it, MathArray::const_iterator end) -{ - docstring s; - for (; it != end && (*it)->asCharInset(); ++it) - s += (*it)->getChar(); - return s; -} - - -void extractStrings(MathArray & ar) -{ - //lyxerr << "\nStrings from: " << ar << endl; - for (size_t i = 0; i < ar.size(); ++i) { - if (!ar[i]->asCharInset()) - continue; - docstring s = charSequence(ar.begin() + i, ar.end()); - ar[i] = MathAtom(new InsetMathString(s)); - ar.erase(i + 1, i + s.size()); - } - //lyxerr << "\nStrings to: " << ar << endl; -} - - -void extractMatrices(MathArray & ar) -{ - //lyxerr << "\nMatrices from: " << ar << endl; - // first pass for explicitly delimited stuff - for (size_t i = 0; i < ar.size(); ++i) { - if (!ar[i]->asDelimInset()) - continue; - MathArray const & arr = ar[i]->asDelimInset()->cell(0); - if (arr.size() != 1) - continue; - if (!arr.front()->asGridInset()) - continue; - ar[i] = MathAtom(new InsetMathMatrix(*(arr.front()->asGridInset()))); - } - - // second pass for AMS "pmatrix" etc - for (size_t i = 0; i < ar.size(); ++i) - if (ar[i]->asAMSArrayInset()) - ar[i] = MathAtom(new InsetMathMatrix(*(ar[i]->asGridInset()))); - //lyxerr << "\nMatrices to: " << ar << endl; -} - - -// convert this inset somehow to a string -bool extractString(MathAtom const & at, docstring & str) -{ - if (at->getChar()) { - str = docstring(1, at->getChar()); - return true; - } - if (at->asStringInset()) { - str = at->asStringInset()->str(); - return true; - } - return false; -} - - -// is this a known function? -bool isKnownFunction(docstring const & str) -{ - for (int i = 0; *function_names[i]; ++i) { - if (str == function_names[i]) - return true; - } - return false; -} - - -// extract a function name from this inset -bool extractFunctionName(MathAtom const & at, docstring & str) -{ - if (at->asSymbolInset()) { - str = at->asSymbolInset()->name(); - return isKnownFunction(str); - } - if (at->asUnknownInset()) { - // assume it is well known... - str = at->name(); - return true; - } - if (at->asFontInset() && at->name() == "mathrm") { - // assume it is well known... - MathArray const & ar = at->asFontInset()->cell(0); - str = charSequence(ar.begin(), ar.end()); - return ar.size() == str.size(); - } - return false; -} - - -// convert this inset somehow to a number -bool extractNumber(MathArray const & ar, int & i) -{ - idocstringstream is(charSequence(ar.begin(), ar.end())); - is >> i; - return is; -} - - -bool extractNumber(MathArray const & ar, double & d) -{ - idocstringstream is(charSequence(ar.begin(), ar.end())); - is >> d; - return is; -} - - -bool testString(MathAtom const & at, docstring const & str) -{ - docstring s; - return extractString(at, s) && str == s; -} - - -bool testString(MathAtom const & at, char const * const str) -{ - return testString(at, from_ascii(str)); -} - -// search end of nested sequence -MathArray::iterator endNestSearch( - MathArray::iterator it, - MathArray::iterator last, - TestItemFunc testOpen, - TestItemFunc testClose -) -{ - for (int level = 0; it != last; ++it) { - if (testOpen(*it)) - ++level; - if (testClose(*it)) - --level; - if (level == 0) - break; - } - return it; -} - - -// replace nested sequences by a real Insets -void replaceNested( - MathArray & ar, - TestItemFunc testOpen, - TestItemFunc testClose, - ReplaceArgumentFunc replaceArg -) -{ - // use indices rather than iterators for the loop because we are going - // to modify the array. - for (size_t i = 0; i < ar.size(); ++i) { - // check whether this is the begin of the sequence - if (!testOpen(ar[i])) - continue; - - // search end of sequence - MathArray::iterator it = ar.begin() + i; - MathArray::iterator jt = endNestSearch(it, ar.end(), testOpen, testClose); - if (jt == ar.end()) - continue; - - // replace the original stuff by the new inset - ar[i] = replaceArg(MathArray(it + 1, jt)); - ar.erase(it + 1, jt + 1); - } -} - - - -// -// split scripts into seperate super- and subscript insets. sub goes in -// front of super... -// - -void splitScripts(MathArray & ar) -{ - //lyxerr << "\nScripts from: " << ar << endl; - for (size_t i = 0; i < ar.size(); ++i) { - InsetMathScript const * script = ar[i]->asScriptInset(); - - // is this a script inset and do we also have a superscript? - if (!script || !script->hasUp()) - continue; - - // we must have a nucleus if we only have a superscript - if (!script->hasDown() && script->nuc().size() == 0) - continue; - - if (script->nuc().size() == 1) { - // leave alone sums and integrals - InsetMathSymbol const * sym = - script->nuc().front()->asSymbolInset(); - if (sym && (sym->name() == "sum" || sym->name() == "int")) - continue; - } - - // create extra script inset and move superscript over - InsetMathScript * p = ar[i].nucleus()->asScriptInset(); - auto_ptr q(new InsetMathScript(true)); - swap(q->up(), p->up()); - p->removeScript(true); - - // if we don't have a subscript, get rid of the ScriptInset - if (!script->hasDown()) { - MathArray arg(p->nuc()); - MathArray::const_iterator it = arg.begin(); - MathArray::const_iterator et = arg.end(); - ar.erase(i); - while (it != et) - ar.insert(i++, *it++); - } else - ++i; - - // insert new inset behind - ar.insert(i, MathAtom(q.release())); - } - //lyxerr << "\nScripts to: " << ar << endl; -} - - -// -// extract exp(...) -// - -void extractExps(MathArray & ar) -{ - //lyxerr << "\nExps from: " << ar << endl; - for (size_t i = 0; i + 1 < ar.size(); ++i) { - // is this 'e'? - if (ar[i]->getChar() != 'e') - continue; - - // we need an exponent but no subscript - InsetMathScript const * sup = ar[i + 1]->asScriptInset(); - if (!sup || sup->hasDown()) - continue; - - // create a proper exp-inset as replacement - ar[i] = MathAtom(new InsetMathExFunc(from_ascii("exp"), sup->cell(1))); - ar.erase(i + 1); - } - //lyxerr << "\nExps to: " << ar << endl; -} - - -// -// extract det(...) from |matrix| -// -void extractDets(MathArray & ar) -{ - //lyxerr << "\ndet from: " << ar << endl; - for (MathArray::iterator it = ar.begin(); it != ar.end(); ++it) { - InsetMathDelim const * del = (*it)->asDelimInset(); - if (!del) - continue; - if (!del->isAbs()) - continue; - *it = MathAtom(new InsetMathExFunc(from_ascii("det"), del->cell(0))); - } - //lyxerr << "\ndet to: " << ar << endl; -} - - -// -// search numbers -// - -bool isDigitOrSimilar(char_type c) -{ - return ('0' <= c && c <= '9') || c == '.'; -} - - -// returns sequence of digits -docstring digitSequence - (MathArray::const_iterator it, MathArray::const_iterator end) -{ - docstring s; - for (; it != end && (*it)->asCharInset(); ++it) { - if (!isDigitOrSimilar((*it)->getChar())) - break; - s += (*it)->getChar(); - } - return s; -} - - -void extractNumbers(MathArray & ar) -{ - //lyxerr << "\nNumbers from: " << ar << endl; - for (size_t i = 0; i < ar.size(); ++i) { - if (!ar[i]->asCharInset()) - continue; - if (!isDigitOrSimilar(ar[i]->asCharInset()->getChar())) - continue; - - docstring s = digitSequence(ar.begin() + i, ar.end()); - - ar[i] = MathAtom(new InsetMathNumber(s)); - ar.erase(i + 1, i + s.size()); - } - //lyxerr << "\nNumbers to: " << ar << endl; -} - - - -// -// search delimiters -// - -bool testOpenParen(MathAtom const & at) -{ - return testString(at, "("); -} - - -bool testCloseParen(MathAtom const & at) -{ - return testString(at, ")"); -} - - -MathAtom replaceParenDelims(const MathArray & ar) -{ - return MathAtom(new InsetMathDelim(from_ascii("("), from_ascii(")"), ar)); -} - - -bool testOpenBracket(MathAtom const & at) -{ - return testString(at, "["); -} - - -bool testCloseBracket(MathAtom const & at) -{ - return testString(at, "]"); -} - - -MathAtom replaceBracketDelims(const MathArray & ar) -{ - return MathAtom(new InsetMathDelim(from_ascii("["), from_ascii("]"), ar)); -} - - -// replace '('...')' and '['...']' sequences by a real InsetMathDelim -void extractDelims(MathArray & ar) -{ - //lyxerr << "\nDelims from: " << ar << endl; - replaceNested(ar, testOpenParen, testCloseParen, replaceParenDelims); - replaceNested(ar, testOpenBracket, testCloseBracket, replaceBracketDelims); - //lyxerr << "\nDelims to: " << ar << endl; -} - - - -// -// search well-known functions -// - - -// replace 'f' '(...)' and 'f' '^n' '(...)' sequences by a real InsetMathExFunc -// assume 'extractDelims' ran before -void extractFunctions(MathArray & ar) -{ - // we need at least two items... - if (ar.size() < 2) - return; - - //lyxerr << "\nFunctions from: " << ar << endl; - for (size_t i = 0; i + 1 < ar.size(); ++i) { - MathArray::iterator it = ar.begin() + i; - MathArray::iterator jt = it + 1; - - docstring name; - // is it a function? - // it certainly is if it is well known... - if (!extractFunctionName(*it, name)) { - // is this a user defined function? - // it it probably not, if it doesn't have a name. - if (!extractString(*it, name)) - continue; - // it is not if it has no argument - if (jt == ar.end()) - continue; - // guess so, if this is followed by - // a DelimInset with a single item in the cell - InsetMathDelim const * del = (*jt)->asDelimInset(); - if (!del || del->cell(0).size() != 1) - continue; - // fall trough into main branch - } - - // do we have an exponent like in - // 'sin' '^2' 'x' -> 'sin(x)' '^2' - MathArray exp; - extractScript(exp, jt, ar.end(), true); - - // create a proper inset as replacement - auto_ptr p(new InsetMathExFunc(name)); - - // jt points to the "argument". Get hold of this. - MathArray::iterator st = extractArgument(p->cell(0), jt, ar.end(), true); - - // replace the function name by a real function inset - *it = MathAtom(p.release()); - - // remove the source of the argument from the array - ar.erase(it + 1, st); - - // re-insert exponent - ar.insert(i + 1, exp); - //lyxerr << "\nFunctions to: " << ar << endl; - } -} - - -// -// search integrals -// - -bool testSymbol(MathAtom const & at, docstring const & name) -{ - return at->asSymbolInset() && at->asSymbolInset()->name() == name; -} - - -bool testSymbol(MathAtom const & at, char const * const name) -{ - return at->asSymbolInset() && at->asSymbolInset()->name() == from_ascii(name); -} - - -bool testIntSymbol(MathAtom const & at) -{ - return testSymbol(at, from_ascii("int")); -} - - -bool testIntegral(MathAtom const & at) -{ - return - testIntSymbol(at) || - ( at->asScriptInset() - && at->asScriptInset()->nuc().size() - && testIntSymbol(at->asScriptInset()->nuc().back()) ); -} - - - -bool testIntDiff(MathAtom const & at) -{ - return testString(at, "d"); -} - - -// replace '\int' ['_^'] x 'd''x'(...)' sequences by a real InsetMathExInt -// assume 'extractDelims' ran before -void extractIntegrals(MathArray & ar) -{ - // we need at least three items... - if (ar.size() < 3) - return; - - //lyxerr << "\nIntegrals from: " << ar << endl; - for (size_t i = 0; i + 1 < ar.size(); ++i) { - MathArray::iterator it = ar.begin() + i; - - // search 'd' - MathArray::iterator jt = - endNestSearch(it, ar.end(), testIntegral, testIntDiff); - - // something sensible found? - if (jt == ar.end()) - continue; - - // is this a integral name? - if (!testIntegral(*it)) - continue; - - // core ist part from behind the scripts to the 'd' - auto_ptr p(new InsetMathExInt(from_ascii("int"))); - - // handle scripts if available - if (!testIntSymbol(*it)) { - p->cell(2) = (*it)->asScriptInset()->down(); - p->cell(3) = (*it)->asScriptInset()->up(); - } - p->cell(0) = MathArray(it + 1, jt); - - // use the "thing" behind the 'd' as differential - MathArray::iterator tt = extractArgument(p->cell(1), jt + 1, ar.end()); - - // remove used parts - ar.erase(it + 1, tt); - *it = MathAtom(p.release()); - } - //lyxerr << "\nIntegrals to: " << ar << endl; -} - - -bool testTermDelimiter(MathAtom const & at) -{ - return testString(at, "+") || testString(at, "-"); -} - - -// try to extract a "term", i.e., something delimited by '+' or '-'. -// returns position behind the term -MathArray::iterator extractTerm(MathArray & ar, - MathArray::iterator pos, MathArray::iterator last) -{ - while (pos != last && !testTermDelimiter(*pos)) { - ar.push_back(*pos); - ++pos; - } - return pos; -} - - -// -// search sums -// - - -bool testEqualSign(MathAtom const & at) -{ - return testString(at, "="); -} - - -bool testSumSymbol(MathAtom const & p) -{ - return testSymbol(p, from_ascii("sum")); -} - - -bool testSum(MathAtom const & at) -{ - return - testSumSymbol(at) || - ( at->asScriptInset() - && at->asScriptInset()->nuc().size() - && testSumSymbol(at->asScriptInset()->nuc().back()) ); -} - - -// replace '\sum' ['_^'] f(x) sequences by a real InsetMathExInt -// assume 'extractDelims' ran before -void extractSums(MathArray & ar) -{ - // we need at least two items... - if (ar.size() < 2) - return; - - //lyxerr << "\nSums from: " << ar << endl; - for (size_t i = 0; i + 1 < ar.size(); ++i) { - MathArray::iterator it = ar.begin() + i; - - // is this a sum name? - if (!testSum(ar[i])) - continue; - - // create a proper inset as replacement - auto_ptr p(new InsetMathExInt(from_ascii("sum"))); - - // collect lower bound and summation index - InsetMathScript const * sub = ar[i]->asScriptInset(); - if (sub && sub->hasDown()) { - // try to figure out the summation index from the subscript - MathArray const & ar = sub->down(); - MathArray::const_iterator xt = - find_if(ar.begin(), ar.end(), &testEqualSign); - if (xt != ar.end()) { - // we found a '=', use everything in front of that as index, - // and everything behind as lower index - p->cell(1) = MathArray(ar.begin(), xt); - p->cell(2) = MathArray(xt + 1, ar.end()); - } else { - // use everything as summation index, don't use scripts. - p->cell(1) = ar; - } - } - - // collect upper bound - if (sub && sub->hasUp()) - p->cell(3) = sub->up(); - - // use something behind the script as core - MathArray::iterator tt = extractTerm(p->cell(0), it + 1, ar.end()); - - // cleanup - ar.erase(it + 1, tt); - *it = MathAtom(p.release()); - } - //lyxerr << "\nSums to: " << ar << endl; -} - - -// -// search differential stuff -// - -// tests for 'd' or '\partial' -bool testDiffItem(MathAtom const & at) -{ - if (testString(at, "d") || testSymbol(at, "partial")) - return true; - - // we may have d^n .../d and splitScripts() has not yet seen it - InsetMathScript const * sup = at->asScriptInset(); - if (sup && !sup->hasDown() && sup->hasUp() && sup->nuc().size() == 1) { - MathAtom const & ma = sup->nuc().front(); - return testString(ma, "d") || testSymbol(ma, "partial"); - } - return false; -} - - -bool testDiffArray(MathArray const & ar) -{ - return ar.size() && testDiffItem(ar.front()); -} - - -bool testDiffFrac(MathAtom const & at) -{ - return - at->asFracInset() - && testDiffArray(at->asFracInset()->cell(0)) - && testDiffArray(at->asFracInset()->cell(1)); -} - - -void extractDiff(MathArray & ar) -{ - //lyxerr << "\nDiffs from: " << ar << endl; - for (size_t i = 0; i < ar.size(); ++i) { - MathArray::iterator it = ar.begin() + i; - - // is this a "differential fraction"? - if (!testDiffFrac(*it)) - continue; - - InsetMathFrac const * f = (*it)->asFracInset(); - if (!f) { - lyxerr << "should not happen" << endl; - continue; - } - - // create a proper diff inset - auto_ptr diff(new InsetMathDiff); - - // collect function, let jt point behind last used item - MathArray::iterator jt = it + 1; - //int n = 1; - MathArray numer(f->cell(0)); - splitScripts(numer); - if (numer.size() > 1 && numer[1]->asScriptInset()) { - // this is something like d^n f(x) / d... or d^n / d... - // FIXME - //n = 1; - if (numer.size() > 2) - diff->cell(0) = MathArray(numer.begin() + 2, numer.end()); - else - jt = extractTerm(diff->cell(0), jt, ar.end()); - } else { - // simply d f(x) / d... or d/d... - if (numer.size() > 1) - diff->cell(0) = MathArray(numer.begin() + 1, numer.end()); - else - jt = extractTerm(diff->cell(0), jt, ar.end()); - } - - // collect denominator parts - MathArray denom(f->cell(1)); - splitScripts(denom); - for (MathArray::iterator dt = denom.begin(); dt != denom.end();) { - // find the next 'd' - MathArray::iterator et - = find_if(dt + 1, denom.end(), &testDiffItem); - - // point before this - MathArray::iterator st = et - 1; - InsetMathScript const * script = (*st)->asScriptInset(); - if (script && script->hasUp()) { - // things like d.../dx^n - int mult = 1; - if (extractNumber(script->up(), mult)) { - //lyxerr << "mult: " << mult << endl; - for (int i = 0; i < mult; ++i) - diff->addDer(MathArray(dt + 1, st)); - } - } else { - // just d.../dx - diff->addDer(MathArray(dt + 1, et)); - } - dt = et; - } - - // cleanup - ar.erase(it + 1, jt); - *it = MathAtom(diff.release()); - } - //lyxerr << "\nDiffs to: " << ar << endl; -} - - -// -// search limits -// - - -bool testRightArrow(MathAtom const & at) -{ - return testSymbol(at, "to") || testSymbol(at, "rightarrow"); -} - - - -// replace '\lim_{x->x0} f(x)' sequences by a real InsetMathLim -// assume 'extractDelims' ran before -void extractLims(MathArray & ar) -{ - //lyxerr << "\nLimits from: " << ar << endl; - for (size_t i = 0; i < ar.size(); ++i) { - MathArray::iterator it = ar.begin() + i; - - // must be a script inset with a subscript (without superscript) - InsetMathScript const * sub = (*it)->asScriptInset(); - if (!sub || !sub->hasDown() || sub->hasUp() || sub->nuc().size() != 1) - continue; - - // is this a limit function? - if (!testSymbol(sub->nuc().front(), "lim")) - continue; - - // subscript must contain a -> symbol - MathArray const & s = sub->down(); - MathArray::const_iterator st = find_if(s.begin(), s.end(), &testRightArrow); - if (st == s.end()) - continue; - - // the -> splits the subscript int x and x0 - MathArray x = MathArray(s.begin(), st); - MathArray x0 = MathArray(st + 1, s.end()); - - // use something behind the script as core - MathArray f; - MathArray::iterator tt = extractTerm(f, it + 1, ar.end()); - - // cleanup - ar.erase(it + 1, tt); - - // create a proper inset as replacement - *it = MathAtom(new InsetMathLim(f, x, x0)); - } - //lyxerr << "\nLimits to: " << ar << endl; -} - - -// -// combine searches -// - -void extractStructure(MathArray & ar) -{ - //lyxerr << "\nStructure from: " << ar << endl; - splitScripts(ar); - extractDelims(ar); - extractIntegrals(ar); - extractSums(ar); - extractNumbers(ar); - extractMatrices(ar); - extractFunctions(ar); - extractDets(ar); - extractDiff(ar); - extractExps(ar); - extractLims(ar); - extractStrings(ar); - //lyxerr << "\nStructure to: " << ar << endl; -} - - -void write(MathArray const & dat, WriteStream & wi) -{ - MathArray ar = dat; - extractStrings(ar); - wi.firstitem() = true; - for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) { - (*it)->write(wi); - wi.firstitem() = false; - } -} - - -void normalize(MathArray const & ar, NormalStream & os) -{ - for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) - (*it)->normalize(os); -} - - -void octave(MathArray const & dat, OctaveStream & os) -{ - MathArray ar = dat; - extractStructure(ar); - for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) - (*it)->octave(os); -} - - -void maple(MathArray const & dat, MapleStream & os) -{ - MathArray ar = dat; - extractStructure(ar); - for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) - (*it)->maple(os); -} - - -void maxima(MathArray const & dat, MaximaStream & os) -{ - MathArray ar = dat; - extractStructure(ar); - for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) - (*it)->maxima(os); -} - - -void mathematica(MathArray const & dat, MathematicaStream & os) -{ - MathArray ar = dat; - extractStructure(ar); - for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) - (*it)->mathematica(os); -} - - -void mathmlize(MathArray const & dat, MathStream & os) -{ - MathArray ar = dat; - extractStructure(ar); - if (ar.size() == 0) - os << ""; - else if (ar.size() == 1) - os << ar.front(); - else { - os << MTag("mrow"); - for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) - (*it)->mathmlize(os); - os << ETag("mrow"); - } -} - - - - -namespace { - - std::string captureOutput(std::string const & cmd, std::string const & data) - { - // In order to avoid parsing problems with command interpreters - // we pass input data through a file - FileName const cas_tmpfile(tempName(FileName(), "casinput")); - if (cas_tmpfile.empty()) { - lyxerr << "Warning: cannot create temporary file." - << endl; - return std::string(); - } - std::ofstream os(cas_tmpfile.toFilesystemEncoding().c_str()); - os << data << endl; - os.close(); - std::string command = cmd + " < " - + quoteName(cas_tmpfile.toFilesystemEncoding()); - lyxerr << "calling: " << cmd - << "\ninput: '" << data << "'" << endl; - cmd_ret const ret = runCommand(command); - unlink(cas_tmpfile); - return ret.second; - } - - size_t get_matching_brace(std::string const & str, size_t i) - { - int count = 1; - size_t n = str.size(); - while (i < n) { - i = str.find_first_of("{}", i+1); - if (i == npos) - return i; - if (str[i] == '{') - ++count; - else - --count; - if (count == 0) - return i; - } - return npos; - } - - size_t get_matching_brace_back(std::string const & str, size_t i) - { - int count = 1; - while (i > 0) { - i = str.find_last_of("{}", i-1); - if (i == npos) - return i; - if (str[i] == '}') - ++count; - else - --count; - if (count == 0) - return i; - } - return npos; - } - - MathArray pipeThroughMaxima(docstring const &, MathArray const & ar) - { - odocstringstream os; - MaximaStream ms(os); - ms << ar; - docstring expr = os.str(); - docstring const header = from_ascii("simpsum:true;"); - - std::string out; - for (int i = 0; i < 100; ++i) { // at most 100 attempts - // try to fix missing '*' the hard way - // - // > echo "2x;" | maxima - // ... - // (C1) Incorrect syntax: x is not an infix operator - // 2x; - // ^ - // - lyxerr << "checking expr: '" << to_utf8(expr) << "'" << endl; - docstring full = header + "tex(" + expr + ");"; - out = captureOutput("maxima", to_utf8(full)); - - // leave loop if expression syntax is probably ok - if (out.find("Incorrect syntax") == npos) - break; - - // search line with "Incorrect syntax" - istringstream is(out); - std::string line; - while (is) { - getline(is, line); - if (line.find("Incorrect syntax") != npos) - break; - } - - // 2nd next line is the one with caret - getline(is, line); - getline(is, line); - size_t pos = line.find('^'); - lyxerr << "found caret at pos: '" << pos << "'" << endl; - if (pos == npos || pos < 4) - break; // caret position not found - pos -= 4; // skip the "tex(" part - if (expr[pos] == '*') - break; // two '*' in a row are definitely bad - expr.insert(pos, from_ascii("*")); - } - - vector tmp = getVectorFromString(out, "$$"); - if (tmp.size() < 2) - return MathArray(); - - out = subst(tmp[1], "\\>", std::string()); - lyxerr << "output: '" << out << "'" << endl; - - // Ugly code that tries to make the result prettier - size_t i = out.find("\\mathchoice"); - while (i != npos) { - size_t j = get_matching_brace(out, i + 12); - size_t k = get_matching_brace(out, j + 1); - k = get_matching_brace(out, k + 1); - k = get_matching_brace(out, k + 1); - std::string mid = out.substr(i + 13, j - i - 13); - if (mid.find("\\over") != npos) - mid = '{' + mid + '}'; - out = out.substr(0,i) - + mid - + out.substr(k + 1); - //lyxerr << "output: " << out << endl; - i = out.find("\\mathchoice", i); - break; - } - - i = out.find("\\over"); - while (i != npos) { - size_t j = get_matching_brace_back(out, i - 1); - if (j == npos || j == 0) - break; - size_t k = get_matching_brace(out, i + 5); - if (k == npos || k + 1 == out.size()) - break; - out = out.substr(0,j - 1) - + "\\frac" - + out.substr(j,i - j) - + out.substr(i + 5,k - i - 4) - + out.substr(k + 2); - //lyxerr << "output: " << out << endl; - i = out.find("\\over", i + 4); - } - MathArray res; - mathed_parse_cell(res, from_utf8(out)); - return res; - } - - - MathArray pipeThroughMaple(docstring const & extra, MathArray const & ar) - { - std::string header = "readlib(latex):\n"; - - // remove the \\it for variable names - //"#`latex/csname_font` := `\\it `:" - header += - "`latex/csname_font` := ``:\n"; - - // export matrices in (...) instead of [...] - header += - "`latex/latex/matrix` := " - "subs(`[`=`(`, `]`=`)`," - "eval(`latex/latex/matrix`)):\n"; - - // replace \\cdots with proper '*' - header += - "`latex/latex/*` := " - "subs(`\\,`=`\\cdot `," - "eval(`latex/latex/*`)):\n"; - - // remove spurious \\noalign{\\medskip} in matrix output - header += - "`latex/latex/matrix`:= " - "subs(`\\\\\\\\\\\\noalign{\\\\medskip}` = `\\\\\\\\`," - "eval(`latex/latex/matrix`)):\n"; - - //"#`latex/latex/symbol` " - // " := subs((\\'_\\' = \\'`\\_`\\',eval(`latex/latex/symbol`)): "; - - std::string trailer = "quit;"; - odocstringstream os; - MapleStream ms(os); - ms << ar; - std::string expr = to_utf8(os.str()); - lyxerr << "ar: '" << ar << "'\n" - << "ms: '" << expr << "'" << endl; - - for (int i = 0; i < 100; ++i) { // at most 100 attempts - // try to fix missing '*' the hard way by using mint - // - // ... > echo "1A;" | mint -i 1 -S -s -q - // on line 1: 1A; - // ^ syntax error - - // Probably missing an operator such as * p - // - lyxerr << "checking expr: '" << expr << "'" << endl; - string out = captureOutput("mint -i 1 -S -s -q -q", expr + ';'); - if (out.empty()) - break; // expression syntax is ok - istringstream is(out); - string line; - getline(is, line); - if (line.find("on line") != 0) - break; // error message not identified - getline(is, line); - size_t pos = line.find('^'); - if (pos == string::npos || pos < 15) - break; // caret position not found - pos -= 15; // skip the "on line ..." part - if (expr[pos] == '*' || (pos > 0 && expr[pos - 1] == '*')) - break; // two '*' in a row are definitely bad - expr.insert(pos, 1, '*'); - } - - // FIXME UNICODE Is utf8 encoding correct? - string full = "latex(" + to_utf8(extra) + '(' + expr + "));"; - string out = captureOutput("maple -q", header + full + trailer); - - // change \_ into _ - - // - MathArray res; - mathed_parse_cell(res, from_utf8(out)); - return res; - } - - - MathArray pipeThroughOctave(docstring const &, MathArray const & ar) - { - odocstringstream os; - OctaveStream vs(os); - vs << ar; - string expr = to_utf8(os.str()); - string out; - - lyxerr << "pipe: ar: '" << ar << "'\n" - << "pipe: expr: '" << expr << "'" << endl; - - for (int i = 0; i < 100; ++i) { // at most 100 attempts - // - // try to fix missing '*' the hard way - // parse error: - // >>> ([[1 2 3 ];[2 3 1 ];[3 1 2 ]])([[1 2 3 ];[2 3 1 ];[3 1 2 ]]) - // ^ - // - lyxerr << "checking expr: '" << expr << "'" << endl; - out = captureOutput("octave -q 2>&1", expr); - lyxerr << "output: '" << out << "'" << endl; - - // leave loop if expression syntax is probably ok - if (out.find("parse error:") == string::npos) - break; - - // search line with single caret - istringstream is(out); - string line; - while (is) { - getline(is, line); - lyxerr << "skipping line: '" << line << "'" << endl; - if (line.find(">>> ") != string::npos) - break; - } - - // found line with error, next line is the one with caret - getline(is, line); - size_t pos = line.find('^'); - lyxerr << "caret line: '" << line << "'" << endl; - lyxerr << "found caret at pos: '" << pos << "'" << endl; - if (pos == string::npos || pos < 4) - break; // caret position not found - pos -= 4; // skip the ">>> " part - if (expr[pos] == '*') - break; // two '*' in a row are definitely bad - expr.insert(pos, 1, '*'); - } - - // remove 'ans = ' taking into account that there may be an - // ansi control sequence before, such as '\033[?1034hans = ' - size_t i = out.find("ans = "); - if (i == string::npos) - return MathArray(); - out = out.substr(i + 6); - - // parse output as matrix or single number - MathAtom at(new InsetMathArray(from_ascii("array"), from_utf8(out))); - InsetMathArray const * mat = at->asArrayInset(); - MathArray res; - if (mat->ncols() == 1 && mat->nrows() == 1) - res.append(mat->cell(0)); - else { - res.push_back(MathAtom(new InsetMathDelim(from_ascii("("), from_ascii(")")))); - res.back().nucleus()->cell(0).push_back(at); - } - return res; - } - - - string fromMathematicaName(string const & name) - { - if (name == "Sin") return "sin"; - if (name == "Sinh") return "sinh"; - if (name == "ArcSin") return "arcsin"; - if (name == "Cos") return "cos"; - if (name == "Cosh") return "cosh"; - if (name == "ArcCos") return "arccos"; - if (name == "Tan") return "tan"; - if (name == "Tanh") return "tanh"; - if (name == "ArcTan") return "arctan"; - if (name == "Cot") return "cot"; - if (name == "Coth") return "coth"; - if (name == "Csc") return "csc"; - if (name == "Sec") return "sec"; - if (name == "Exp") return "exp"; - if (name == "Log") return "log"; - if (name == "Arg" ) return "arg"; - if (name == "Det" ) return "det"; - if (name == "GCD" ) return "gcd"; - if (name == "Max" ) return "max"; - if (name == "Min" ) return "min"; - if (name == "Erf" ) return "erf"; - if (name == "Erfc" ) return "erfc"; - return name; - } - - - void prettifyMathematicaOutput(string & out, string const & macroName, - bool roman, bool translate) - { - string const macro = "\\" + macroName + "{"; - size_t const len = macro.length(); - size_t i = out.find(macro); - - while (i != npos) { - size_t const j = get_matching_brace(out, i + len); - string const name = out.substr(i + len, j - i - len); - out = out.substr(0, i) - + (roman ? "\\mathrm{" : "") - + (translate ? fromMathematicaName(name) : name) - + out.substr(roman ? j : j + 1); - //lyxerr << "output: " << out << endl; - i = out.find(macro, i); - } - } - - - MathArray pipeThroughMathematica(docstring const &, MathArray const & ar) - { - odocstringstream os; - MathematicaStream ms(os); - ms << ar; - // FIXME UNICODE Is utf8 encoding correct? - string const expr = to_utf8(os.str()); - string out; - - lyxerr << "expr: '" << expr << "'" << endl; - - string const full = "TeXForm[" + expr + "]"; - out = captureOutput("math", full); - lyxerr << "output: '" << out << "'" << endl; - - size_t pos1 = out.find("Out[1]//TeXForm= "); - size_t pos2 = out.find("In[2]:="); - - if (pos1 == string::npos || pos2 == string::npos) - return MathArray(); - - // get everything from pos1+17 to pos2 - out = out.substr(pos1 + 17, pos2 - pos1 - 17); - out = subst(subst(out, '\r', ' '), '\n', ' '); - - // tries to make the result prettier - prettifyMathematicaOutput(out, "Mfunction", true, true); - prettifyMathematicaOutput(out, "Muserfunction", true, false); - prettifyMathematicaOutput(out, "Mvariable", false, false); - - MathArray res; - mathed_parse_cell(res, from_utf8(out)); - return res; - } - -} - - -MathArray pipeThroughExtern(string const & lang, docstring const & extra, - MathArray const & ar) -{ - if (lang == "octave") - return pipeThroughOctave(extra, ar); - - if (lang == "maxima") - return pipeThroughMaxima(extra, ar); - - if (lang == "maple") - return pipeThroughMaple(extra, ar); - - if (lang == "mathematica") - return pipeThroughMathematica(extra, ar); - - // create normalized expression - odocstringstream os; - NormalStream ns(os); - os << '[' << extra << ' '; - ns << ar; - os << ']'; - // FIXME UNICODE Is utf8 encoding correct? - string data = to_utf8(os.str()); - - // search external script - support::FileName const file = libFileSearch("mathed", "extern_" + lang); - if (file.empty()) { - lyxerr << "converter to '" << lang << "' not found" << endl; - return MathArray(); - } - - // run external sript - string out = captureOutput(file.absFilename(), data); - MathArray res; - mathed_parse_cell(res, from_utf8(out)); - return res; -} - - -} // namespace lyx diff --git a/src/mathed/MathExtern.cpp b/src/mathed/MathExtern.cpp new file mode 100644 index 0000000000..36ca80104e --- /dev/null +++ b/src/mathed/MathExtern.cpp @@ -0,0 +1,1452 @@ +/** + * \file MathExtern.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +// This file contains most of the magic that extracts "context +// information" from the unstructered layout-oriented stuff in an +// MathArray. + +#include + +#include "MathExtern.h" +#include "InsetMathArray.h" +#include "InsetMathChar.h" +#include "InsetMathDelim.h" +#include "MathData.h" +#include "InsetMathDiff.h" +#include "InsetMathExFunc.h" +#include "InsetMathExInt.h" +#include "InsetMathFont.h" +#include "InsetMathFrac.h" +#include "InsetMathLim.h" +#include "InsetMathMatrix.h" +#include "MathStream.h" +#include "InsetMathNumber.h" +#include "InsetMathScript.h" +#include "InsetMathString.h" +#include "InsetMathSymbol.h" +#include "MathParser.h" +#include "debug.h" +#include "support/filetools.h" +#include "support/lstrings.h" +#include "support/lyxlib.h" +#include "frontends/controllers/ControlMath.h" + +#include +#include +#include + + +namespace lyx { + +using support::cmd_ret; +using support::getVectorFromString; +using support::libFileSearch; +using support::runCommand; +using support::FileName; +using support::quoteName; +using support::tempName; +using support::unlink; +using support::subst; + +using frontend::function_names; + +using std::endl; +using std::find_if; +using std::auto_ptr; +using std::istringstream; +using std::ostream; +using std::swap; +using std::string; +using std::vector; + +static size_t const npos = lyx::docstring::npos; + +// define a function for tests +typedef bool TestItemFunc(MathAtom const &); + +// define a function for replacing subexpressions +typedef MathAtom ReplaceArgumentFunc(const MathArray & ar); + + + +// try to extract a super/subscript +// modify iterator position to point behind the thing +bool extractScript(MathArray & ar, + MathArray::iterator & pos, MathArray::iterator last, bool superscript) +{ + // nothing to get here + if (pos == last) + return false; + + // is this a scriptinset? + if (!(*pos)->asScriptInset()) + return false; + + // do we want superscripts only? + if (superscript && !(*pos)->asScriptInset()->hasUp()) + return false; + + // it is a scriptinset, use it. + ar.push_back(*pos); + ++pos; + return true; +} + + +// try to extract an "argument" to some function. +// returns position behind the argument +MathArray::iterator extractArgument(MathArray & ar, + MathArray::iterator pos, MathArray::iterator last, bool function = false) +{ + // nothing to get here + if (pos == last) + return pos; + + // something delimited _is_ an argument + if ((*pos)->asDelimInset()) { + // leave out delimiters if this is a function argument + if (function) { + MathArray const & arg = (*pos)->asDelimInset()->cell(0); + MathArray::const_iterator cur = arg.begin(); + MathArray::const_iterator end = arg.end(); + while (cur != end) + ar.push_back(*cur++); + } else + ar.push_back(*pos); + ++pos; + if (pos == last) + return pos; + // if there's one, get following superscript only if this + // isn't a function argument + if (!function) + extractScript(ar, pos, last, true); + return pos; + } + + // always take the first thing, no matter what it is + ar.push_back(*pos); + + // go ahead if possible + ++pos; + if (pos == last) + return pos; + + // if the next item is a super/subscript, it most certainly belongs + // to the thing we have + extractScript(ar, pos, last, false); + if (pos == last) + return pos; + + // but it might be more than that. + // FIXME: not implemented + //for (MathArray::iterator it = pos + 1; it != last; ++it) { + // // always take the first thing, no matter + // if (it == pos) { + // ar.push_back(*it); + // continue; + // } + //} + return pos; +} + + +// returns sequence of char with same code starting at it up to end +// it might be less, though... +docstring charSequence + (MathArray::const_iterator it, MathArray::const_iterator end) +{ + docstring s; + for (; it != end && (*it)->asCharInset(); ++it) + s += (*it)->getChar(); + return s; +} + + +void extractStrings(MathArray & ar) +{ + //lyxerr << "\nStrings from: " << ar << endl; + for (size_t i = 0; i < ar.size(); ++i) { + if (!ar[i]->asCharInset()) + continue; + docstring s = charSequence(ar.begin() + i, ar.end()); + ar[i] = MathAtom(new InsetMathString(s)); + ar.erase(i + 1, i + s.size()); + } + //lyxerr << "\nStrings to: " << ar << endl; +} + + +void extractMatrices(MathArray & ar) +{ + //lyxerr << "\nMatrices from: " << ar << endl; + // first pass for explicitly delimited stuff + for (size_t i = 0; i < ar.size(); ++i) { + if (!ar[i]->asDelimInset()) + continue; + MathArray const & arr = ar[i]->asDelimInset()->cell(0); + if (arr.size() != 1) + continue; + if (!arr.front()->asGridInset()) + continue; + ar[i] = MathAtom(new InsetMathMatrix(*(arr.front()->asGridInset()))); + } + + // second pass for AMS "pmatrix" etc + for (size_t i = 0; i < ar.size(); ++i) + if (ar[i]->asAMSArrayInset()) + ar[i] = MathAtom(new InsetMathMatrix(*(ar[i]->asGridInset()))); + //lyxerr << "\nMatrices to: " << ar << endl; +} + + +// convert this inset somehow to a string +bool extractString(MathAtom const & at, docstring & str) +{ + if (at->getChar()) { + str = docstring(1, at->getChar()); + return true; + } + if (at->asStringInset()) { + str = at->asStringInset()->str(); + return true; + } + return false; +} + + +// is this a known function? +bool isKnownFunction(docstring const & str) +{ + for (int i = 0; *function_names[i]; ++i) { + if (str == function_names[i]) + return true; + } + return false; +} + + +// extract a function name from this inset +bool extractFunctionName(MathAtom const & at, docstring & str) +{ + if (at->asSymbolInset()) { + str = at->asSymbolInset()->name(); + return isKnownFunction(str); + } + if (at->asUnknownInset()) { + // assume it is well known... + str = at->name(); + return true; + } + if (at->asFontInset() && at->name() == "mathrm") { + // assume it is well known... + MathArray const & ar = at->asFontInset()->cell(0); + str = charSequence(ar.begin(), ar.end()); + return ar.size() == str.size(); + } + return false; +} + + +// convert this inset somehow to a number +bool extractNumber(MathArray const & ar, int & i) +{ + idocstringstream is(charSequence(ar.begin(), ar.end())); + is >> i; + return is; +} + + +bool extractNumber(MathArray const & ar, double & d) +{ + idocstringstream is(charSequence(ar.begin(), ar.end())); + is >> d; + return is; +} + + +bool testString(MathAtom const & at, docstring const & str) +{ + docstring s; + return extractString(at, s) && str == s; +} + + +bool testString(MathAtom const & at, char const * const str) +{ + return testString(at, from_ascii(str)); +} + +// search end of nested sequence +MathArray::iterator endNestSearch( + MathArray::iterator it, + MathArray::iterator last, + TestItemFunc testOpen, + TestItemFunc testClose +) +{ + for (int level = 0; it != last; ++it) { + if (testOpen(*it)) + ++level; + if (testClose(*it)) + --level; + if (level == 0) + break; + } + return it; +} + + +// replace nested sequences by a real Insets +void replaceNested( + MathArray & ar, + TestItemFunc testOpen, + TestItemFunc testClose, + ReplaceArgumentFunc replaceArg +) +{ + // use indices rather than iterators for the loop because we are going + // to modify the array. + for (size_t i = 0; i < ar.size(); ++i) { + // check whether this is the begin of the sequence + if (!testOpen(ar[i])) + continue; + + // search end of sequence + MathArray::iterator it = ar.begin() + i; + MathArray::iterator jt = endNestSearch(it, ar.end(), testOpen, testClose); + if (jt == ar.end()) + continue; + + // replace the original stuff by the new inset + ar[i] = replaceArg(MathArray(it + 1, jt)); + ar.erase(it + 1, jt + 1); + } +} + + + +// +// split scripts into seperate super- and subscript insets. sub goes in +// front of super... +// + +void splitScripts(MathArray & ar) +{ + //lyxerr << "\nScripts from: " << ar << endl; + for (size_t i = 0; i < ar.size(); ++i) { + InsetMathScript const * script = ar[i]->asScriptInset(); + + // is this a script inset and do we also have a superscript? + if (!script || !script->hasUp()) + continue; + + // we must have a nucleus if we only have a superscript + if (!script->hasDown() && script->nuc().size() == 0) + continue; + + if (script->nuc().size() == 1) { + // leave alone sums and integrals + InsetMathSymbol const * sym = + script->nuc().front()->asSymbolInset(); + if (sym && (sym->name() == "sum" || sym->name() == "int")) + continue; + } + + // create extra script inset and move superscript over + InsetMathScript * p = ar[i].nucleus()->asScriptInset(); + auto_ptr q(new InsetMathScript(true)); + swap(q->up(), p->up()); + p->removeScript(true); + + // if we don't have a subscript, get rid of the ScriptInset + if (!script->hasDown()) { + MathArray arg(p->nuc()); + MathArray::const_iterator it = arg.begin(); + MathArray::const_iterator et = arg.end(); + ar.erase(i); + while (it != et) + ar.insert(i++, *it++); + } else + ++i; + + // insert new inset behind + ar.insert(i, MathAtom(q.release())); + } + //lyxerr << "\nScripts to: " << ar << endl; +} + + +// +// extract exp(...) +// + +void extractExps(MathArray & ar) +{ + //lyxerr << "\nExps from: " << ar << endl; + for (size_t i = 0; i + 1 < ar.size(); ++i) { + // is this 'e'? + if (ar[i]->getChar() != 'e') + continue; + + // we need an exponent but no subscript + InsetMathScript const * sup = ar[i + 1]->asScriptInset(); + if (!sup || sup->hasDown()) + continue; + + // create a proper exp-inset as replacement + ar[i] = MathAtom(new InsetMathExFunc(from_ascii("exp"), sup->cell(1))); + ar.erase(i + 1); + } + //lyxerr << "\nExps to: " << ar << endl; +} + + +// +// extract det(...) from |matrix| +// +void extractDets(MathArray & ar) +{ + //lyxerr << "\ndet from: " << ar << endl; + for (MathArray::iterator it = ar.begin(); it != ar.end(); ++it) { + InsetMathDelim const * del = (*it)->asDelimInset(); + if (!del) + continue; + if (!del->isAbs()) + continue; + *it = MathAtom(new InsetMathExFunc(from_ascii("det"), del->cell(0))); + } + //lyxerr << "\ndet to: " << ar << endl; +} + + +// +// search numbers +// + +bool isDigitOrSimilar(char_type c) +{ + return ('0' <= c && c <= '9') || c == '.'; +} + + +// returns sequence of digits +docstring digitSequence + (MathArray::const_iterator it, MathArray::const_iterator end) +{ + docstring s; + for (; it != end && (*it)->asCharInset(); ++it) { + if (!isDigitOrSimilar((*it)->getChar())) + break; + s += (*it)->getChar(); + } + return s; +} + + +void extractNumbers(MathArray & ar) +{ + //lyxerr << "\nNumbers from: " << ar << endl; + for (size_t i = 0; i < ar.size(); ++i) { + if (!ar[i]->asCharInset()) + continue; + if (!isDigitOrSimilar(ar[i]->asCharInset()->getChar())) + continue; + + docstring s = digitSequence(ar.begin() + i, ar.end()); + + ar[i] = MathAtom(new InsetMathNumber(s)); + ar.erase(i + 1, i + s.size()); + } + //lyxerr << "\nNumbers to: " << ar << endl; +} + + + +// +// search delimiters +// + +bool testOpenParen(MathAtom const & at) +{ + return testString(at, "("); +} + + +bool testCloseParen(MathAtom const & at) +{ + return testString(at, ")"); +} + + +MathAtom replaceParenDelims(const MathArray & ar) +{ + return MathAtom(new InsetMathDelim(from_ascii("("), from_ascii(")"), ar)); +} + + +bool testOpenBracket(MathAtom const & at) +{ + return testString(at, "["); +} + + +bool testCloseBracket(MathAtom const & at) +{ + return testString(at, "]"); +} + + +MathAtom replaceBracketDelims(const MathArray & ar) +{ + return MathAtom(new InsetMathDelim(from_ascii("["), from_ascii("]"), ar)); +} + + +// replace '('...')' and '['...']' sequences by a real InsetMathDelim +void extractDelims(MathArray & ar) +{ + //lyxerr << "\nDelims from: " << ar << endl; + replaceNested(ar, testOpenParen, testCloseParen, replaceParenDelims); + replaceNested(ar, testOpenBracket, testCloseBracket, replaceBracketDelims); + //lyxerr << "\nDelims to: " << ar << endl; +} + + + +// +// search well-known functions +// + + +// replace 'f' '(...)' and 'f' '^n' '(...)' sequences by a real InsetMathExFunc +// assume 'extractDelims' ran before +void extractFunctions(MathArray & ar) +{ + // we need at least two items... + if (ar.size() < 2) + return; + + //lyxerr << "\nFunctions from: " << ar << endl; + for (size_t i = 0; i + 1 < ar.size(); ++i) { + MathArray::iterator it = ar.begin() + i; + MathArray::iterator jt = it + 1; + + docstring name; + // is it a function? + // it certainly is if it is well known... + if (!extractFunctionName(*it, name)) { + // is this a user defined function? + // it it probably not, if it doesn't have a name. + if (!extractString(*it, name)) + continue; + // it is not if it has no argument + if (jt == ar.end()) + continue; + // guess so, if this is followed by + // a DelimInset with a single item in the cell + InsetMathDelim const * del = (*jt)->asDelimInset(); + if (!del || del->cell(0).size() != 1) + continue; + // fall trough into main branch + } + + // do we have an exponent like in + // 'sin' '^2' 'x' -> 'sin(x)' '^2' + MathArray exp; + extractScript(exp, jt, ar.end(), true); + + // create a proper inset as replacement + auto_ptr p(new InsetMathExFunc(name)); + + // jt points to the "argument". Get hold of this. + MathArray::iterator st = extractArgument(p->cell(0), jt, ar.end(), true); + + // replace the function name by a real function inset + *it = MathAtom(p.release()); + + // remove the source of the argument from the array + ar.erase(it + 1, st); + + // re-insert exponent + ar.insert(i + 1, exp); + //lyxerr << "\nFunctions to: " << ar << endl; + } +} + + +// +// search integrals +// + +bool testSymbol(MathAtom const & at, docstring const & name) +{ + return at->asSymbolInset() && at->asSymbolInset()->name() == name; +} + + +bool testSymbol(MathAtom const & at, char const * const name) +{ + return at->asSymbolInset() && at->asSymbolInset()->name() == from_ascii(name); +} + + +bool testIntSymbol(MathAtom const & at) +{ + return testSymbol(at, from_ascii("int")); +} + + +bool testIntegral(MathAtom const & at) +{ + return + testIntSymbol(at) || + ( at->asScriptInset() + && at->asScriptInset()->nuc().size() + && testIntSymbol(at->asScriptInset()->nuc().back()) ); +} + + + +bool testIntDiff(MathAtom const & at) +{ + return testString(at, "d"); +} + + +// replace '\int' ['_^'] x 'd''x'(...)' sequences by a real InsetMathExInt +// assume 'extractDelims' ran before +void extractIntegrals(MathArray & ar) +{ + // we need at least three items... + if (ar.size() < 3) + return; + + //lyxerr << "\nIntegrals from: " << ar << endl; + for (size_t i = 0; i + 1 < ar.size(); ++i) { + MathArray::iterator it = ar.begin() + i; + + // search 'd' + MathArray::iterator jt = + endNestSearch(it, ar.end(), testIntegral, testIntDiff); + + // something sensible found? + if (jt == ar.end()) + continue; + + // is this a integral name? + if (!testIntegral(*it)) + continue; + + // core ist part from behind the scripts to the 'd' + auto_ptr p(new InsetMathExInt(from_ascii("int"))); + + // handle scripts if available + if (!testIntSymbol(*it)) { + p->cell(2) = (*it)->asScriptInset()->down(); + p->cell(3) = (*it)->asScriptInset()->up(); + } + p->cell(0) = MathArray(it + 1, jt); + + // use the "thing" behind the 'd' as differential + MathArray::iterator tt = extractArgument(p->cell(1), jt + 1, ar.end()); + + // remove used parts + ar.erase(it + 1, tt); + *it = MathAtom(p.release()); + } + //lyxerr << "\nIntegrals to: " << ar << endl; +} + + +bool testTermDelimiter(MathAtom const & at) +{ + return testString(at, "+") || testString(at, "-"); +} + + +// try to extract a "term", i.e., something delimited by '+' or '-'. +// returns position behind the term +MathArray::iterator extractTerm(MathArray & ar, + MathArray::iterator pos, MathArray::iterator last) +{ + while (pos != last && !testTermDelimiter(*pos)) { + ar.push_back(*pos); + ++pos; + } + return pos; +} + + +// +// search sums +// + + +bool testEqualSign(MathAtom const & at) +{ + return testString(at, "="); +} + + +bool testSumSymbol(MathAtom const & p) +{ + return testSymbol(p, from_ascii("sum")); +} + + +bool testSum(MathAtom const & at) +{ + return + testSumSymbol(at) || + ( at->asScriptInset() + && at->asScriptInset()->nuc().size() + && testSumSymbol(at->asScriptInset()->nuc().back()) ); +} + + +// replace '\sum' ['_^'] f(x) sequences by a real InsetMathExInt +// assume 'extractDelims' ran before +void extractSums(MathArray & ar) +{ + // we need at least two items... + if (ar.size() < 2) + return; + + //lyxerr << "\nSums from: " << ar << endl; + for (size_t i = 0; i + 1 < ar.size(); ++i) { + MathArray::iterator it = ar.begin() + i; + + // is this a sum name? + if (!testSum(ar[i])) + continue; + + // create a proper inset as replacement + auto_ptr p(new InsetMathExInt(from_ascii("sum"))); + + // collect lower bound and summation index + InsetMathScript const * sub = ar[i]->asScriptInset(); + if (sub && sub->hasDown()) { + // try to figure out the summation index from the subscript + MathArray const & ar = sub->down(); + MathArray::const_iterator xt = + find_if(ar.begin(), ar.end(), &testEqualSign); + if (xt != ar.end()) { + // we found a '=', use everything in front of that as index, + // and everything behind as lower index + p->cell(1) = MathArray(ar.begin(), xt); + p->cell(2) = MathArray(xt + 1, ar.end()); + } else { + // use everything as summation index, don't use scripts. + p->cell(1) = ar; + } + } + + // collect upper bound + if (sub && sub->hasUp()) + p->cell(3) = sub->up(); + + // use something behind the script as core + MathArray::iterator tt = extractTerm(p->cell(0), it + 1, ar.end()); + + // cleanup + ar.erase(it + 1, tt); + *it = MathAtom(p.release()); + } + //lyxerr << "\nSums to: " << ar << endl; +} + + +// +// search differential stuff +// + +// tests for 'd' or '\partial' +bool testDiffItem(MathAtom const & at) +{ + if (testString(at, "d") || testSymbol(at, "partial")) + return true; + + // we may have d^n .../d and splitScripts() has not yet seen it + InsetMathScript const * sup = at->asScriptInset(); + if (sup && !sup->hasDown() && sup->hasUp() && sup->nuc().size() == 1) { + MathAtom const & ma = sup->nuc().front(); + return testString(ma, "d") || testSymbol(ma, "partial"); + } + return false; +} + + +bool testDiffArray(MathArray const & ar) +{ + return ar.size() && testDiffItem(ar.front()); +} + + +bool testDiffFrac(MathAtom const & at) +{ + return + at->asFracInset() + && testDiffArray(at->asFracInset()->cell(0)) + && testDiffArray(at->asFracInset()->cell(1)); +} + + +void extractDiff(MathArray & ar) +{ + //lyxerr << "\nDiffs from: " << ar << endl; + for (size_t i = 0; i < ar.size(); ++i) { + MathArray::iterator it = ar.begin() + i; + + // is this a "differential fraction"? + if (!testDiffFrac(*it)) + continue; + + InsetMathFrac const * f = (*it)->asFracInset(); + if (!f) { + lyxerr << "should not happen" << endl; + continue; + } + + // create a proper diff inset + auto_ptr diff(new InsetMathDiff); + + // collect function, let jt point behind last used item + MathArray::iterator jt = it + 1; + //int n = 1; + MathArray numer(f->cell(0)); + splitScripts(numer); + if (numer.size() > 1 && numer[1]->asScriptInset()) { + // this is something like d^n f(x) / d... or d^n / d... + // FIXME + //n = 1; + if (numer.size() > 2) + diff->cell(0) = MathArray(numer.begin() + 2, numer.end()); + else + jt = extractTerm(diff->cell(0), jt, ar.end()); + } else { + // simply d f(x) / d... or d/d... + if (numer.size() > 1) + diff->cell(0) = MathArray(numer.begin() + 1, numer.end()); + else + jt = extractTerm(diff->cell(0), jt, ar.end()); + } + + // collect denominator parts + MathArray denom(f->cell(1)); + splitScripts(denom); + for (MathArray::iterator dt = denom.begin(); dt != denom.end();) { + // find the next 'd' + MathArray::iterator et + = find_if(dt + 1, denom.end(), &testDiffItem); + + // point before this + MathArray::iterator st = et - 1; + InsetMathScript const * script = (*st)->asScriptInset(); + if (script && script->hasUp()) { + // things like d.../dx^n + int mult = 1; + if (extractNumber(script->up(), mult)) { + //lyxerr << "mult: " << mult << endl; + for (int i = 0; i < mult; ++i) + diff->addDer(MathArray(dt + 1, st)); + } + } else { + // just d.../dx + diff->addDer(MathArray(dt + 1, et)); + } + dt = et; + } + + // cleanup + ar.erase(it + 1, jt); + *it = MathAtom(diff.release()); + } + //lyxerr << "\nDiffs to: " << ar << endl; +} + + +// +// search limits +// + + +bool testRightArrow(MathAtom const & at) +{ + return testSymbol(at, "to") || testSymbol(at, "rightarrow"); +} + + + +// replace '\lim_{x->x0} f(x)' sequences by a real InsetMathLim +// assume 'extractDelims' ran before +void extractLims(MathArray & ar) +{ + //lyxerr << "\nLimits from: " << ar << endl; + for (size_t i = 0; i < ar.size(); ++i) { + MathArray::iterator it = ar.begin() + i; + + // must be a script inset with a subscript (without superscript) + InsetMathScript const * sub = (*it)->asScriptInset(); + if (!sub || !sub->hasDown() || sub->hasUp() || sub->nuc().size() != 1) + continue; + + // is this a limit function? + if (!testSymbol(sub->nuc().front(), "lim")) + continue; + + // subscript must contain a -> symbol + MathArray const & s = sub->down(); + MathArray::const_iterator st = find_if(s.begin(), s.end(), &testRightArrow); + if (st == s.end()) + continue; + + // the -> splits the subscript int x and x0 + MathArray x = MathArray(s.begin(), st); + MathArray x0 = MathArray(st + 1, s.end()); + + // use something behind the script as core + MathArray f; + MathArray::iterator tt = extractTerm(f, it + 1, ar.end()); + + // cleanup + ar.erase(it + 1, tt); + + // create a proper inset as replacement + *it = MathAtom(new InsetMathLim(f, x, x0)); + } + //lyxerr << "\nLimits to: " << ar << endl; +} + + +// +// combine searches +// + +void extractStructure(MathArray & ar) +{ + //lyxerr << "\nStructure from: " << ar << endl; + splitScripts(ar); + extractDelims(ar); + extractIntegrals(ar); + extractSums(ar); + extractNumbers(ar); + extractMatrices(ar); + extractFunctions(ar); + extractDets(ar); + extractDiff(ar); + extractExps(ar); + extractLims(ar); + extractStrings(ar); + //lyxerr << "\nStructure to: " << ar << endl; +} + + +void write(MathArray const & dat, WriteStream & wi) +{ + MathArray ar = dat; + extractStrings(ar); + wi.firstitem() = true; + for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) { + (*it)->write(wi); + wi.firstitem() = false; + } +} + + +void normalize(MathArray const & ar, NormalStream & os) +{ + for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) + (*it)->normalize(os); +} + + +void octave(MathArray const & dat, OctaveStream & os) +{ + MathArray ar = dat; + extractStructure(ar); + for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) + (*it)->octave(os); +} + + +void maple(MathArray const & dat, MapleStream & os) +{ + MathArray ar = dat; + extractStructure(ar); + for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) + (*it)->maple(os); +} + + +void maxima(MathArray const & dat, MaximaStream & os) +{ + MathArray ar = dat; + extractStructure(ar); + for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) + (*it)->maxima(os); +} + + +void mathematica(MathArray const & dat, MathematicaStream & os) +{ + MathArray ar = dat; + extractStructure(ar); + for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) + (*it)->mathematica(os); +} + + +void mathmlize(MathArray const & dat, MathStream & os) +{ + MathArray ar = dat; + extractStructure(ar); + if (ar.size() == 0) + os << ""; + else if (ar.size() == 1) + os << ar.front(); + else { + os << MTag("mrow"); + for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) + (*it)->mathmlize(os); + os << ETag("mrow"); + } +} + + + + +namespace { + + std::string captureOutput(std::string const & cmd, std::string const & data) + { + // In order to avoid parsing problems with command interpreters + // we pass input data through a file + FileName const cas_tmpfile(tempName(FileName(), "casinput")); + if (cas_tmpfile.empty()) { + lyxerr << "Warning: cannot create temporary file." + << endl; + return std::string(); + } + std::ofstream os(cas_tmpfile.toFilesystemEncoding().c_str()); + os << data << endl; + os.close(); + std::string command = cmd + " < " + + quoteName(cas_tmpfile.toFilesystemEncoding()); + lyxerr << "calling: " << cmd + << "\ninput: '" << data << "'" << endl; + cmd_ret const ret = runCommand(command); + unlink(cas_tmpfile); + return ret.second; + } + + size_t get_matching_brace(std::string const & str, size_t i) + { + int count = 1; + size_t n = str.size(); + while (i < n) { + i = str.find_first_of("{}", i+1); + if (i == npos) + return i; + if (str[i] == '{') + ++count; + else + --count; + if (count == 0) + return i; + } + return npos; + } + + size_t get_matching_brace_back(std::string const & str, size_t i) + { + int count = 1; + while (i > 0) { + i = str.find_last_of("{}", i-1); + if (i == npos) + return i; + if (str[i] == '}') + ++count; + else + --count; + if (count == 0) + return i; + } + return npos; + } + + MathArray pipeThroughMaxima(docstring const &, MathArray const & ar) + { + odocstringstream os; + MaximaStream ms(os); + ms << ar; + docstring expr = os.str(); + docstring const header = from_ascii("simpsum:true;"); + + std::string out; + for (int i = 0; i < 100; ++i) { // at most 100 attempts + // try to fix missing '*' the hard way + // + // > echo "2x;" | maxima + // ... + // (C1) Incorrect syntax: x is not an infix operator + // 2x; + // ^ + // + lyxerr << "checking expr: '" << to_utf8(expr) << "'" << endl; + docstring full = header + "tex(" + expr + ");"; + out = captureOutput("maxima", to_utf8(full)); + + // leave loop if expression syntax is probably ok + if (out.find("Incorrect syntax") == npos) + break; + + // search line with "Incorrect syntax" + istringstream is(out); + std::string line; + while (is) { + getline(is, line); + if (line.find("Incorrect syntax") != npos) + break; + } + + // 2nd next line is the one with caret + getline(is, line); + getline(is, line); + size_t pos = line.find('^'); + lyxerr << "found caret at pos: '" << pos << "'" << endl; + if (pos == npos || pos < 4) + break; // caret position not found + pos -= 4; // skip the "tex(" part + if (expr[pos] == '*') + break; // two '*' in a row are definitely bad + expr.insert(pos, from_ascii("*")); + } + + vector tmp = getVectorFromString(out, "$$"); + if (tmp.size() < 2) + return MathArray(); + + out = subst(tmp[1], "\\>", std::string()); + lyxerr << "output: '" << out << "'" << endl; + + // Ugly code that tries to make the result prettier + size_t i = out.find("\\mathchoice"); + while (i != npos) { + size_t j = get_matching_brace(out, i + 12); + size_t k = get_matching_brace(out, j + 1); + k = get_matching_brace(out, k + 1); + k = get_matching_brace(out, k + 1); + std::string mid = out.substr(i + 13, j - i - 13); + if (mid.find("\\over") != npos) + mid = '{' + mid + '}'; + out = out.substr(0,i) + + mid + + out.substr(k + 1); + //lyxerr << "output: " << out << endl; + i = out.find("\\mathchoice", i); + break; + } + + i = out.find("\\over"); + while (i != npos) { + size_t j = get_matching_brace_back(out, i - 1); + if (j == npos || j == 0) + break; + size_t k = get_matching_brace(out, i + 5); + if (k == npos || k + 1 == out.size()) + break; + out = out.substr(0,j - 1) + + "\\frac" + + out.substr(j,i - j) + + out.substr(i + 5,k - i - 4) + + out.substr(k + 2); + //lyxerr << "output: " << out << endl; + i = out.find("\\over", i + 4); + } + MathArray res; + mathed_parse_cell(res, from_utf8(out)); + return res; + } + + + MathArray pipeThroughMaple(docstring const & extra, MathArray const & ar) + { + std::string header = "readlib(latex):\n"; + + // remove the \\it for variable names + //"#`latex/csname_font` := `\\it `:" + header += + "`latex/csname_font` := ``:\n"; + + // export matrices in (...) instead of [...] + header += + "`latex/latex/matrix` := " + "subs(`[`=`(`, `]`=`)`," + "eval(`latex/latex/matrix`)):\n"; + + // replace \\cdots with proper '*' + header += + "`latex/latex/*` := " + "subs(`\\,`=`\\cdot `," + "eval(`latex/latex/*`)):\n"; + + // remove spurious \\noalign{\\medskip} in matrix output + header += + "`latex/latex/matrix`:= " + "subs(`\\\\\\\\\\\\noalign{\\\\medskip}` = `\\\\\\\\`," + "eval(`latex/latex/matrix`)):\n"; + + //"#`latex/latex/symbol` " + // " := subs((\\'_\\' = \\'`\\_`\\',eval(`latex/latex/symbol`)): "; + + std::string trailer = "quit;"; + odocstringstream os; + MapleStream ms(os); + ms << ar; + std::string expr = to_utf8(os.str()); + lyxerr << "ar: '" << ar << "'\n" + << "ms: '" << expr << "'" << endl; + + for (int i = 0; i < 100; ++i) { // at most 100 attempts + // try to fix missing '*' the hard way by using mint + // + // ... > echo "1A;" | mint -i 1 -S -s -q + // on line 1: 1A; + // ^ syntax error - + // Probably missing an operator such as * p + // + lyxerr << "checking expr: '" << expr << "'" << endl; + string out = captureOutput("mint -i 1 -S -s -q -q", expr + ';'); + if (out.empty()) + break; // expression syntax is ok + istringstream is(out); + string line; + getline(is, line); + if (line.find("on line") != 0) + break; // error message not identified + getline(is, line); + size_t pos = line.find('^'); + if (pos == string::npos || pos < 15) + break; // caret position not found + pos -= 15; // skip the "on line ..." part + if (expr[pos] == '*' || (pos > 0 && expr[pos - 1] == '*')) + break; // two '*' in a row are definitely bad + expr.insert(pos, 1, '*'); + } + + // FIXME UNICODE Is utf8 encoding correct? + string full = "latex(" + to_utf8(extra) + '(' + expr + "));"; + string out = captureOutput("maple -q", header + full + trailer); + + // change \_ into _ + + // + MathArray res; + mathed_parse_cell(res, from_utf8(out)); + return res; + } + + + MathArray pipeThroughOctave(docstring const &, MathArray const & ar) + { + odocstringstream os; + OctaveStream vs(os); + vs << ar; + string expr = to_utf8(os.str()); + string out; + + lyxerr << "pipe: ar: '" << ar << "'\n" + << "pipe: expr: '" << expr << "'" << endl; + + for (int i = 0; i < 100; ++i) { // at most 100 attempts + // + // try to fix missing '*' the hard way + // parse error: + // >>> ([[1 2 3 ];[2 3 1 ];[3 1 2 ]])([[1 2 3 ];[2 3 1 ];[3 1 2 ]]) + // ^ + // + lyxerr << "checking expr: '" << expr << "'" << endl; + out = captureOutput("octave -q 2>&1", expr); + lyxerr << "output: '" << out << "'" << endl; + + // leave loop if expression syntax is probably ok + if (out.find("parse error:") == string::npos) + break; + + // search line with single caret + istringstream is(out); + string line; + while (is) { + getline(is, line); + lyxerr << "skipping line: '" << line << "'" << endl; + if (line.find(">>> ") != string::npos) + break; + } + + // found line with error, next line is the one with caret + getline(is, line); + size_t pos = line.find('^'); + lyxerr << "caret line: '" << line << "'" << endl; + lyxerr << "found caret at pos: '" << pos << "'" << endl; + if (pos == string::npos || pos < 4) + break; // caret position not found + pos -= 4; // skip the ">>> " part + if (expr[pos] == '*') + break; // two '*' in a row are definitely bad + expr.insert(pos, 1, '*'); + } + + // remove 'ans = ' taking into account that there may be an + // ansi control sequence before, such as '\033[?1034hans = ' + size_t i = out.find("ans = "); + if (i == string::npos) + return MathArray(); + out = out.substr(i + 6); + + // parse output as matrix or single number + MathAtom at(new InsetMathArray(from_ascii("array"), from_utf8(out))); + InsetMathArray const * mat = at->asArrayInset(); + MathArray res; + if (mat->ncols() == 1 && mat->nrows() == 1) + res.append(mat->cell(0)); + else { + res.push_back(MathAtom(new InsetMathDelim(from_ascii("("), from_ascii(")")))); + res.back().nucleus()->cell(0).push_back(at); + } + return res; + } + + + string fromMathematicaName(string const & name) + { + if (name == "Sin") return "sin"; + if (name == "Sinh") return "sinh"; + if (name == "ArcSin") return "arcsin"; + if (name == "Cos") return "cos"; + if (name == "Cosh") return "cosh"; + if (name == "ArcCos") return "arccos"; + if (name == "Tan") return "tan"; + if (name == "Tanh") return "tanh"; + if (name == "ArcTan") return "arctan"; + if (name == "Cot") return "cot"; + if (name == "Coth") return "coth"; + if (name == "Csc") return "csc"; + if (name == "Sec") return "sec"; + if (name == "Exp") return "exp"; + if (name == "Log") return "log"; + if (name == "Arg" ) return "arg"; + if (name == "Det" ) return "det"; + if (name == "GCD" ) return "gcd"; + if (name == "Max" ) return "max"; + if (name == "Min" ) return "min"; + if (name == "Erf" ) return "erf"; + if (name == "Erfc" ) return "erfc"; + return name; + } + + + void prettifyMathematicaOutput(string & out, string const & macroName, + bool roman, bool translate) + { + string const macro = "\\" + macroName + "{"; + size_t const len = macro.length(); + size_t i = out.find(macro); + + while (i != npos) { + size_t const j = get_matching_brace(out, i + len); + string const name = out.substr(i + len, j - i - len); + out = out.substr(0, i) + + (roman ? "\\mathrm{" : "") + + (translate ? fromMathematicaName(name) : name) + + out.substr(roman ? j : j + 1); + //lyxerr << "output: " << out << endl; + i = out.find(macro, i); + } + } + + + MathArray pipeThroughMathematica(docstring const &, MathArray const & ar) + { + odocstringstream os; + MathematicaStream ms(os); + ms << ar; + // FIXME UNICODE Is utf8 encoding correct? + string const expr = to_utf8(os.str()); + string out; + + lyxerr << "expr: '" << expr << "'" << endl; + + string const full = "TeXForm[" + expr + "]"; + out = captureOutput("math", full); + lyxerr << "output: '" << out << "'" << endl; + + size_t pos1 = out.find("Out[1]//TeXForm= "); + size_t pos2 = out.find("In[2]:="); + + if (pos1 == string::npos || pos2 == string::npos) + return MathArray(); + + // get everything from pos1+17 to pos2 + out = out.substr(pos1 + 17, pos2 - pos1 - 17); + out = subst(subst(out, '\r', ' '), '\n', ' '); + + // tries to make the result prettier + prettifyMathematicaOutput(out, "Mfunction", true, true); + prettifyMathematicaOutput(out, "Muserfunction", true, false); + prettifyMathematicaOutput(out, "Mvariable", false, false); + + MathArray res; + mathed_parse_cell(res, from_utf8(out)); + return res; + } + +} + + +MathArray pipeThroughExtern(string const & lang, docstring const & extra, + MathArray const & ar) +{ + if (lang == "octave") + return pipeThroughOctave(extra, ar); + + if (lang == "maxima") + return pipeThroughMaxima(extra, ar); + + if (lang == "maple") + return pipeThroughMaple(extra, ar); + + if (lang == "mathematica") + return pipeThroughMathematica(extra, ar); + + // create normalized expression + odocstringstream os; + NormalStream ns(os); + os << '[' << extra << ' '; + ns << ar; + os << ']'; + // FIXME UNICODE Is utf8 encoding correct? + string data = to_utf8(os.str()); + + // search external script + support::FileName const file = libFileSearch("mathed", "extern_" + lang); + if (file.empty()) { + lyxerr << "converter to '" << lang << "' not found" << endl; + return MathArray(); + } + + // run external sript + string out = captureOutput(file.absFilename(), data); + MathArray res; + mathed_parse_cell(res, from_utf8(out)); + return res; +} + + +} // namespace lyx diff --git a/src/mathed/MathFactory.C b/src/mathed/MathFactory.C deleted file mode 100644 index 6cb6e702ba..0000000000 --- a/src/mathed/MathFactory.C +++ /dev/null @@ -1,428 +0,0 @@ -/** - * \file MathFactory.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "MathFactory.h" - -#include "InsetMathAMSArray.h" -#include "InsetMathArray.h" -#include "InsetMathBinom.h" -#include "InsetMathBoldSymbol.h" -#include "InsetMathBoxed.h" -#include "InsetMathBox.h" -#include "InsetMathCases.h" -#include "InsetMathColor.h" -#include "InsetMathDecoration.h" -#include "InsetMathDFrac.h" -#include "InsetMathDots.h" -#include "InsetMathFBox.h" -#include "InsetMathFont.h" -#include "InsetMathFontOld.h" -#include "InsetMathFrac.h" -#include "InsetMathFrameBox.h" -#include "InsetMathKern.h" -#include "InsetMathLefteqn.h" -#include "InsetMathMacro.h" -#include "InsetMathMakebox.h" -#include "InsetMathOverset.h" -#include "InsetMathPhantom.h" -#include "InsetMathRef.h" -#include "InsetMathRoot.h" -#include "InsetMathSize.h" -#include "InsetMathSpace.h" -#include "InsetMathSplit.h" -#include "InsetMathSqrt.h" -#include "InsetMathStackrel.h" -#include "InsetMathSubstack.h" -#include "InsetMathSymbol.h" -#include "InsetMathTabular.h" -#include "InsetMathTFrac.h" -#include "InsetMathUnderset.h" -#include "InsetMathUnknown.h" -#include "InsetMathXArrow.h" -#include "InsetMathXYMatrix.h" -#include "MathMacroArgument.h" -#include "MathMacroTable.h" -#include "MathParser.h" -#include "MathSupport.h" - -#include "debug.h" - -#include "insets/InsetCommand.h" - -#include "support/filetools.h" // LibFileSearch -#include "support/lstrings.h" - -#include "frontends/FontLoader.h" - - -namespace lyx { - -using support::libFileSearch; -using support::split; - -using std::string; -using std::endl; -using std::istringstream; -using std::vector; - -bool has_math_fonts; - - -namespace { - -// file scope -typedef std::map WordList; - -WordList theWordList; - - -bool math_font_available(docstring & name) -{ - LyXFont f; - augmentFont(f, name); - - // Do we have the font proper? - if (theFontLoader().available(f)) - return true; - - // can we fake it? - if (name == "eufrak") { - name = from_ascii("lyxfakefrak"); - return true; - } - - LYXERR(Debug::MATHED) - << "font " << to_utf8(name) << " not available and I can't fake it" - << endl; - return false; -} - - -void initSymbols() -{ - support::FileName const filename = libFileSearch(string(), "symbols"); - LYXERR(Debug::MATHED) << "read symbols from " << filename << endl; - if (filename.empty()) { - lyxerr << "Could not find symbols file" << endl; - return; - } - - std::ifstream fs(filename.toFilesystemEncoding().c_str()); - string line; - bool skip = false; - while (getline(fs, line)) { - int charid = 0; - int fallbackid = 0; - if (line.empty() || line[0] == '#') - continue; - - // special case of iffont/else/endif - if (line.size() >= 7 && line.substr(0, 6) == "iffont") { - istringstream is(line); - string tmp; - is >> tmp; - is >> tmp; - docstring t = from_utf8(tmp); - skip = !math_font_available(t); - continue; - } else if (line.size() >= 4 && line.substr(0, 4) == "else") { - skip = !skip; - } else if (line.size() >= 5 && line.substr(0, 5) == "endif") { - skip = false; - continue; - } else if (skip) - continue; - - // special case of pre-defined macros - if (line.size() > 8 && line.substr(0, 5) == "\\def\\") { - //lyxerr << "macro definition: '" << line << '\'' << endl; - istringstream is(line); - string macro; - string requires; - is >> macro >> requires; - MacroTable::globalMacros().insert(from_utf8(macro), requires); - continue; - } - - idocstringstream is(from_utf8(line)); - latexkeys tmp; - is >> tmp.name >> tmp.inset; - if (isFontName(tmp.inset)) - is >> charid >> fallbackid >> tmp.extra >> tmp.xmlname; - else - is >> tmp.extra; - // requires is optional - if (is) - is >> tmp.requires; - else { - LYXERR(Debug::MATHED) << "skipping line '" << line << '\'' << endl; - LYXERR(Debug::MATHED) - << to_utf8(tmp.name) << ' ' << to_utf8(tmp.inset) << ' ' << to_utf8(tmp.extra) << endl; - continue; - } - - if (isFontName(tmp.inset)) { - // tmp.inset _is_ the fontname here. - // create fallbacks if necessary - - // store requirements as long as we can - if (tmp.requires.empty() && - (tmp.inset == "msa" || tmp.inset == "msb")) - tmp.requires = from_ascii("amssymb"); - else if (tmp.inset == "wasy") - tmp.requires = from_ascii("wasysym"); - - // symbol font is not available sometimes - docstring symbol_font = from_ascii("lyxsymbol"); - - if (tmp.extra == "func" || tmp.extra == "funclim" || tmp.extra == "special") { - LYXERR(Debug::MATHED) << "symbol abuse for " << to_utf8(tmp.name) << endl; - tmp.draw = tmp.name; - } else if (math_font_available(tmp.inset)) { - LYXERR(Debug::MATHED) << "symbol available for " << to_utf8(tmp.name) << endl; - tmp.draw.push_back(char_type(charid)); - } else if (fallbackid && math_font_available(symbol_font)) { - if (tmp.inset == "cmex") - tmp.inset = from_ascii("lyxsymbol"); - else - tmp.inset = from_ascii("lyxboldsymbol"); - LYXERR(Debug::MATHED) << "symbol fallback for " << to_utf8(tmp.name) << endl; - tmp.draw.push_back(char_type(fallbackid)); - } else { - LYXERR(Debug::MATHED) << "faking " << to_utf8(tmp.name) << endl; - tmp.draw = tmp.name; - tmp.inset = from_ascii("lyxtex"); - } - } else { - // it's a proper inset - LYXERR(Debug::MATHED) << "inset " << to_utf8(tmp.inset) - << " used for " << to_utf8(tmp.name) - << endl; - } - - if (theWordList.find(tmp.name) != theWordList.end()) - LYXERR(Debug::MATHED) - << "readSymbols: inset " << to_utf8(tmp.name) - << " already exists." << endl; - else - theWordList[tmp.name] = tmp; - - LYXERR(Debug::MATHED) - << "read symbol '" << to_utf8(tmp.name) - << " inset: " << to_utf8(tmp.inset) - << " draw: " << int(tmp.draw.empty() ? 0 : tmp.draw[0]) - << " extra: " << to_utf8(tmp.extra) - << " requires: " << to_utf8(tmp.requires) - << '\'' << endl; - } - docstring tmp = from_ascii("cmm"); - docstring tmp2 = from_ascii("cmsy"); - has_math_fonts = math_font_available(tmp) && math_font_available(tmp2); -} - - -} // namespace anon - - -void initMath() -{ - static bool initialized = false; - if (!initialized) { - initialized = true; - initParser(); - initSymbols(); - } -} - - -latexkeys const * in_word_set(docstring const & str) -{ - WordList::iterator it = theWordList.find(str); - return it != theWordList.end() ? &(it->second) : 0; -} - - -MathAtom createInsetMath(char const * const s) -{ - return createInsetMath(from_utf8(s)); -} - - -MathAtom createInsetMath(docstring const & s) -{ - //lyxerr << "creating inset with name: '" << s << '\'' << endl; - latexkeys const * l = in_word_set(s); - if (l) { - docstring const & inset = l->inset; - //lyxerr << " found inset: '" << inset << '\'' << endl; - if (inset == "ref") - return MathAtom(new RefInset(l->name)); - if (inset == "overset") - return MathAtom(new InsetMathOverset); - if (inset == "underset") - return MathAtom(new InsetMathUnderset); - if (inset == "decoration") - return MathAtom(new InsetMathDecoration(l)); - if (inset == "space") - return MathAtom(new InsetMathSpace(l->name)); - if (inset == "dots") - return MathAtom(new InsetMathDots(l)); - if (inset == "mbox") - // return MathAtom(new InsetMathMBox); - // InsetMathMBox is proposed to replace InsetMathBox, - // but is not ready yet (it needs a BufferView for - // construction) - return MathAtom(new InsetMathBox(l->name)); -// if (inset == "fbox") -// return MathAtom(new InsetMathFBox(l)); - if (inset == "style") - return MathAtom(new InsetMathSize(l)); - if (inset == "font") - return MathAtom(new InsetMathFont(l)); - if (inset == "oldfont") - return MathAtom(new InsetMathFontOld(l)); - if (inset == "matrix") - return MathAtom(new InsetMathAMSArray(s)); - if (inset == "split") - return MathAtom(new InsetMathSplit(s)); - if (inset == "big") - // we can't create a InsetMathBig, since the argument - // is missing. - return MathAtom(new InsetMathUnknown(s)); - return MathAtom(new InsetMathSymbol(l)); - } - - if (s.size() == 2 && s[0] == '#' && s[1] >= '1' && s[1] <= '9') - return MathAtom(new MathMacroArgument(s[1] - '0')); - if (s.size() == 3 && s[0] == '\\' && s[1] == '#' - && s[2] >= '1' && s[2] <= '9') - return MathAtom(new MathMacroArgument(s[2] - '0')); - if (s == "boxed") - return MathAtom(new InsetMathBoxed()); - if (s == "fbox") - return MathAtom(new InsetMathFBox()); - if (s == "framebox") - return MathAtom(new InsetMathFrameBox); - if (s == "makebox") - return MathAtom(new InsetMathMakebox); - if (s == "kern") - return MathAtom(new InsetMathKern); - if (s.substr(0, 8) == "xymatrix") { - char spacing_code = '\0'; - LyXLength spacing; - size_t const len = s.length(); - size_t i = 8; - if (i < len && s[i] == '@') { - ++i; - if (i < len) { - switch (s[i]) { - case 'R': - case 'C': - case 'M': - case 'W': - case 'H': - case 'L': - spacing_code = static_cast(s[i]); - ++i; - break; - } - } - if (i < len && s[i] == '=') { - ++i; - spacing = LyXLength(to_ascii(s.substr(i))); - } - } - return MathAtom(new InsetMathXYMatrix(spacing, spacing_code)); - } - if (s == "xrightarrow" || s == "xleftarrow") - return MathAtom(new InsetMathXArrow(s)); - if (s == "split" || s == "gathered" || s == "aligned" || s == "alignedat") - return MathAtom(new InsetMathSplit(s)); - if (s == "cases") - return MathAtom(new InsetMathCases); - if (s == "substack") - return MathAtom(new InsetMathSubstack); - if (s == "subarray" || s == "array") - return MathAtom(new InsetMathArray(s, 1, 1)); - if (s == "sqrt") - return MathAtom(new InsetMathSqrt); - if (s == "root") - return MathAtom(new InsetMathRoot); - if (s == "tabular") - return MathAtom(new InsetMathTabular(s, 1, 1)); - if (s == "stackrel") - return MathAtom(new InsetMathStackrel); - if (s == "binom" || s == "choose") - return MathAtom(new InsetMathBinom(s == "choose")); - if (s == "frac") - return MathAtom(new InsetMathFrac); - if (s == "over") - return MathAtom(new InsetMathFrac(InsetMathFrac::OVER)); - if (s == "nicefrac") - return MathAtom(new InsetMathFrac(InsetMathFrac::NICEFRAC)); - //if (s == "infer") - // return MathAtom(new MathInferInset); - if (s == "atop") - return MathAtom(new InsetMathFrac(InsetMathFrac::ATOP)); - if (s == "lefteqn") - return MathAtom(new InsetMathLefteqn); - if (s == "boldsymbol") - return MathAtom(new InsetMathBoldSymbol); - if (s == "color" || s == "normalcolor") - return MathAtom(new InsetMathColor(true)); - if (s == "textcolor") - return MathAtom(new InsetMathColor(false)); - if (s == "dfrac") - return MathAtom(new InsetMathDFrac); - if (s == "tfrac") - return MathAtom(new InsetMathTFrac); - if (s == "hphantom") - return MathAtom(new InsetMathPhantom(InsetMathPhantom::hphantom)); - if (s == "phantom") - return MathAtom(new InsetMathPhantom(InsetMathPhantom::phantom)); - if (s == "vphantom") - return MathAtom(new InsetMathPhantom(InsetMathPhantom::vphantom)); - - if (MacroTable::globalMacros().has(s)) - return MathAtom(new MathMacro(s, - MacroTable::globalMacros().get(s).numargs())); - //if (MacroTable::localMacros().has(s)) - // return MathAtom(new MathMacro(s, - // MacroTable::localMacros().get(s).numargs())); - - //lyxerr << "creating unknown inset '" << s << "'" << endl; - return MathAtom(new InsetMathUnknown(s)); -} - - -bool createInsetMath_fromDialogStr(docstring const & str, MathArray & ar) -{ - // An example str: - // "ref LatexCommand ref\nreference \"sec:Title\"\n\\end_inset\n\n"; - docstring name; - docstring body = split(str, name, ' '); - - if (name != "ref" ) - return false; - - InsetCommandParams icp("ref"); - // FIXME UNICODE - InsetCommandMailer::string2params("ref", to_utf8(str), icp); - mathed_parse_cell(ar, icp.getCommand()); - if (ar.size() != 1) - return false; - - return ar[0].nucleus(); -} - - -} // namespace lyx diff --git a/src/mathed/MathFactory.cpp b/src/mathed/MathFactory.cpp new file mode 100644 index 0000000000..6cb6e702ba --- /dev/null +++ b/src/mathed/MathFactory.cpp @@ -0,0 +1,428 @@ +/** + * \file MathFactory.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "MathFactory.h" + +#include "InsetMathAMSArray.h" +#include "InsetMathArray.h" +#include "InsetMathBinom.h" +#include "InsetMathBoldSymbol.h" +#include "InsetMathBoxed.h" +#include "InsetMathBox.h" +#include "InsetMathCases.h" +#include "InsetMathColor.h" +#include "InsetMathDecoration.h" +#include "InsetMathDFrac.h" +#include "InsetMathDots.h" +#include "InsetMathFBox.h" +#include "InsetMathFont.h" +#include "InsetMathFontOld.h" +#include "InsetMathFrac.h" +#include "InsetMathFrameBox.h" +#include "InsetMathKern.h" +#include "InsetMathLefteqn.h" +#include "InsetMathMacro.h" +#include "InsetMathMakebox.h" +#include "InsetMathOverset.h" +#include "InsetMathPhantom.h" +#include "InsetMathRef.h" +#include "InsetMathRoot.h" +#include "InsetMathSize.h" +#include "InsetMathSpace.h" +#include "InsetMathSplit.h" +#include "InsetMathSqrt.h" +#include "InsetMathStackrel.h" +#include "InsetMathSubstack.h" +#include "InsetMathSymbol.h" +#include "InsetMathTabular.h" +#include "InsetMathTFrac.h" +#include "InsetMathUnderset.h" +#include "InsetMathUnknown.h" +#include "InsetMathXArrow.h" +#include "InsetMathXYMatrix.h" +#include "MathMacroArgument.h" +#include "MathMacroTable.h" +#include "MathParser.h" +#include "MathSupport.h" + +#include "debug.h" + +#include "insets/InsetCommand.h" + +#include "support/filetools.h" // LibFileSearch +#include "support/lstrings.h" + +#include "frontends/FontLoader.h" + + +namespace lyx { + +using support::libFileSearch; +using support::split; + +using std::string; +using std::endl; +using std::istringstream; +using std::vector; + +bool has_math_fonts; + + +namespace { + +// file scope +typedef std::map WordList; + +WordList theWordList; + + +bool math_font_available(docstring & name) +{ + LyXFont f; + augmentFont(f, name); + + // Do we have the font proper? + if (theFontLoader().available(f)) + return true; + + // can we fake it? + if (name == "eufrak") { + name = from_ascii("lyxfakefrak"); + return true; + } + + LYXERR(Debug::MATHED) + << "font " << to_utf8(name) << " not available and I can't fake it" + << endl; + return false; +} + + +void initSymbols() +{ + support::FileName const filename = libFileSearch(string(), "symbols"); + LYXERR(Debug::MATHED) << "read symbols from " << filename << endl; + if (filename.empty()) { + lyxerr << "Could not find symbols file" << endl; + return; + } + + std::ifstream fs(filename.toFilesystemEncoding().c_str()); + string line; + bool skip = false; + while (getline(fs, line)) { + int charid = 0; + int fallbackid = 0; + if (line.empty() || line[0] == '#') + continue; + + // special case of iffont/else/endif + if (line.size() >= 7 && line.substr(0, 6) == "iffont") { + istringstream is(line); + string tmp; + is >> tmp; + is >> tmp; + docstring t = from_utf8(tmp); + skip = !math_font_available(t); + continue; + } else if (line.size() >= 4 && line.substr(0, 4) == "else") { + skip = !skip; + } else if (line.size() >= 5 && line.substr(0, 5) == "endif") { + skip = false; + continue; + } else if (skip) + continue; + + // special case of pre-defined macros + if (line.size() > 8 && line.substr(0, 5) == "\\def\\") { + //lyxerr << "macro definition: '" << line << '\'' << endl; + istringstream is(line); + string macro; + string requires; + is >> macro >> requires; + MacroTable::globalMacros().insert(from_utf8(macro), requires); + continue; + } + + idocstringstream is(from_utf8(line)); + latexkeys tmp; + is >> tmp.name >> tmp.inset; + if (isFontName(tmp.inset)) + is >> charid >> fallbackid >> tmp.extra >> tmp.xmlname; + else + is >> tmp.extra; + // requires is optional + if (is) + is >> tmp.requires; + else { + LYXERR(Debug::MATHED) << "skipping line '" << line << '\'' << endl; + LYXERR(Debug::MATHED) + << to_utf8(tmp.name) << ' ' << to_utf8(tmp.inset) << ' ' << to_utf8(tmp.extra) << endl; + continue; + } + + if (isFontName(tmp.inset)) { + // tmp.inset _is_ the fontname here. + // create fallbacks if necessary + + // store requirements as long as we can + if (tmp.requires.empty() && + (tmp.inset == "msa" || tmp.inset == "msb")) + tmp.requires = from_ascii("amssymb"); + else if (tmp.inset == "wasy") + tmp.requires = from_ascii("wasysym"); + + // symbol font is not available sometimes + docstring symbol_font = from_ascii("lyxsymbol"); + + if (tmp.extra == "func" || tmp.extra == "funclim" || tmp.extra == "special") { + LYXERR(Debug::MATHED) << "symbol abuse for " << to_utf8(tmp.name) << endl; + tmp.draw = tmp.name; + } else if (math_font_available(tmp.inset)) { + LYXERR(Debug::MATHED) << "symbol available for " << to_utf8(tmp.name) << endl; + tmp.draw.push_back(char_type(charid)); + } else if (fallbackid && math_font_available(symbol_font)) { + if (tmp.inset == "cmex") + tmp.inset = from_ascii("lyxsymbol"); + else + tmp.inset = from_ascii("lyxboldsymbol"); + LYXERR(Debug::MATHED) << "symbol fallback for " << to_utf8(tmp.name) << endl; + tmp.draw.push_back(char_type(fallbackid)); + } else { + LYXERR(Debug::MATHED) << "faking " << to_utf8(tmp.name) << endl; + tmp.draw = tmp.name; + tmp.inset = from_ascii("lyxtex"); + } + } else { + // it's a proper inset + LYXERR(Debug::MATHED) << "inset " << to_utf8(tmp.inset) + << " used for " << to_utf8(tmp.name) + << endl; + } + + if (theWordList.find(tmp.name) != theWordList.end()) + LYXERR(Debug::MATHED) + << "readSymbols: inset " << to_utf8(tmp.name) + << " already exists." << endl; + else + theWordList[tmp.name] = tmp; + + LYXERR(Debug::MATHED) + << "read symbol '" << to_utf8(tmp.name) + << " inset: " << to_utf8(tmp.inset) + << " draw: " << int(tmp.draw.empty() ? 0 : tmp.draw[0]) + << " extra: " << to_utf8(tmp.extra) + << " requires: " << to_utf8(tmp.requires) + << '\'' << endl; + } + docstring tmp = from_ascii("cmm"); + docstring tmp2 = from_ascii("cmsy"); + has_math_fonts = math_font_available(tmp) && math_font_available(tmp2); +} + + +} // namespace anon + + +void initMath() +{ + static bool initialized = false; + if (!initialized) { + initialized = true; + initParser(); + initSymbols(); + } +} + + +latexkeys const * in_word_set(docstring const & str) +{ + WordList::iterator it = theWordList.find(str); + return it != theWordList.end() ? &(it->second) : 0; +} + + +MathAtom createInsetMath(char const * const s) +{ + return createInsetMath(from_utf8(s)); +} + + +MathAtom createInsetMath(docstring const & s) +{ + //lyxerr << "creating inset with name: '" << s << '\'' << endl; + latexkeys const * l = in_word_set(s); + if (l) { + docstring const & inset = l->inset; + //lyxerr << " found inset: '" << inset << '\'' << endl; + if (inset == "ref") + return MathAtom(new RefInset(l->name)); + if (inset == "overset") + return MathAtom(new InsetMathOverset); + if (inset == "underset") + return MathAtom(new InsetMathUnderset); + if (inset == "decoration") + return MathAtom(new InsetMathDecoration(l)); + if (inset == "space") + return MathAtom(new InsetMathSpace(l->name)); + if (inset == "dots") + return MathAtom(new InsetMathDots(l)); + if (inset == "mbox") + // return MathAtom(new InsetMathMBox); + // InsetMathMBox is proposed to replace InsetMathBox, + // but is not ready yet (it needs a BufferView for + // construction) + return MathAtom(new InsetMathBox(l->name)); +// if (inset == "fbox") +// return MathAtom(new InsetMathFBox(l)); + if (inset == "style") + return MathAtom(new InsetMathSize(l)); + if (inset == "font") + return MathAtom(new InsetMathFont(l)); + if (inset == "oldfont") + return MathAtom(new InsetMathFontOld(l)); + if (inset == "matrix") + return MathAtom(new InsetMathAMSArray(s)); + if (inset == "split") + return MathAtom(new InsetMathSplit(s)); + if (inset == "big") + // we can't create a InsetMathBig, since the argument + // is missing. + return MathAtom(new InsetMathUnknown(s)); + return MathAtom(new InsetMathSymbol(l)); + } + + if (s.size() == 2 && s[0] == '#' && s[1] >= '1' && s[1] <= '9') + return MathAtom(new MathMacroArgument(s[1] - '0')); + if (s.size() == 3 && s[0] == '\\' && s[1] == '#' + && s[2] >= '1' && s[2] <= '9') + return MathAtom(new MathMacroArgument(s[2] - '0')); + if (s == "boxed") + return MathAtom(new InsetMathBoxed()); + if (s == "fbox") + return MathAtom(new InsetMathFBox()); + if (s == "framebox") + return MathAtom(new InsetMathFrameBox); + if (s == "makebox") + return MathAtom(new InsetMathMakebox); + if (s == "kern") + return MathAtom(new InsetMathKern); + if (s.substr(0, 8) == "xymatrix") { + char spacing_code = '\0'; + LyXLength spacing; + size_t const len = s.length(); + size_t i = 8; + if (i < len && s[i] == '@') { + ++i; + if (i < len) { + switch (s[i]) { + case 'R': + case 'C': + case 'M': + case 'W': + case 'H': + case 'L': + spacing_code = static_cast(s[i]); + ++i; + break; + } + } + if (i < len && s[i] == '=') { + ++i; + spacing = LyXLength(to_ascii(s.substr(i))); + } + } + return MathAtom(new InsetMathXYMatrix(spacing, spacing_code)); + } + if (s == "xrightarrow" || s == "xleftarrow") + return MathAtom(new InsetMathXArrow(s)); + if (s == "split" || s == "gathered" || s == "aligned" || s == "alignedat") + return MathAtom(new InsetMathSplit(s)); + if (s == "cases") + return MathAtom(new InsetMathCases); + if (s == "substack") + return MathAtom(new InsetMathSubstack); + if (s == "subarray" || s == "array") + return MathAtom(new InsetMathArray(s, 1, 1)); + if (s == "sqrt") + return MathAtom(new InsetMathSqrt); + if (s == "root") + return MathAtom(new InsetMathRoot); + if (s == "tabular") + return MathAtom(new InsetMathTabular(s, 1, 1)); + if (s == "stackrel") + return MathAtom(new InsetMathStackrel); + if (s == "binom" || s == "choose") + return MathAtom(new InsetMathBinom(s == "choose")); + if (s == "frac") + return MathAtom(new InsetMathFrac); + if (s == "over") + return MathAtom(new InsetMathFrac(InsetMathFrac::OVER)); + if (s == "nicefrac") + return MathAtom(new InsetMathFrac(InsetMathFrac::NICEFRAC)); + //if (s == "infer") + // return MathAtom(new MathInferInset); + if (s == "atop") + return MathAtom(new InsetMathFrac(InsetMathFrac::ATOP)); + if (s == "lefteqn") + return MathAtom(new InsetMathLefteqn); + if (s == "boldsymbol") + return MathAtom(new InsetMathBoldSymbol); + if (s == "color" || s == "normalcolor") + return MathAtom(new InsetMathColor(true)); + if (s == "textcolor") + return MathAtom(new InsetMathColor(false)); + if (s == "dfrac") + return MathAtom(new InsetMathDFrac); + if (s == "tfrac") + return MathAtom(new InsetMathTFrac); + if (s == "hphantom") + return MathAtom(new InsetMathPhantom(InsetMathPhantom::hphantom)); + if (s == "phantom") + return MathAtom(new InsetMathPhantom(InsetMathPhantom::phantom)); + if (s == "vphantom") + return MathAtom(new InsetMathPhantom(InsetMathPhantom::vphantom)); + + if (MacroTable::globalMacros().has(s)) + return MathAtom(new MathMacro(s, + MacroTable::globalMacros().get(s).numargs())); + //if (MacroTable::localMacros().has(s)) + // return MathAtom(new MathMacro(s, + // MacroTable::localMacros().get(s).numargs())); + + //lyxerr << "creating unknown inset '" << s << "'" << endl; + return MathAtom(new InsetMathUnknown(s)); +} + + +bool createInsetMath_fromDialogStr(docstring const & str, MathArray & ar) +{ + // An example str: + // "ref LatexCommand ref\nreference \"sec:Title\"\n\\end_inset\n\n"; + docstring name; + docstring body = split(str, name, ' '); + + if (name != "ref" ) + return false; + + InsetCommandParams icp("ref"); + // FIXME UNICODE + InsetCommandMailer::string2params("ref", to_utf8(str), icp); + mathed_parse_cell(ar, icp.getCommand()); + if (ar.size() != 1) + return false; + + return ar[0].nucleus(); +} + + +} // namespace lyx diff --git a/src/mathed/MathMacroArgument.C b/src/mathed/MathMacroArgument.C deleted file mode 100644 index 4d2badb9e0..0000000000 --- a/src/mathed/MathMacroArgument.C +++ /dev/null @@ -1,80 +0,0 @@ -/** - * \file MathMacroArgument.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Alejandro Aguilar Sierra - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "MathMacroArgument.h" -#include "MathStream.h" -#include "MathSupport.h" -#include "debug.h" - - -namespace lyx { - -using std::endl; -using std::auto_ptr; -using std::size_t; -using std::vector; - - -MathMacroArgument::MathMacroArgument(size_t n) - : number_(n) -{ - if (n < 1 || n > 9) { - lyxerr << "MathMacroArgument::MathMacroArgument: wrong Argument id: " - << n << endl; - } - // The profiler tells us not to use - // str_ = '#' + convert(n); - // so we do the conversion of n to ASCII manually. - // This works because 1 <= n <= 9. - str_.resize(2); - str_[0] = '#'; - str_[1] = '0' + n; -} - - -auto_ptr MathMacroArgument::doClone() const -{ - return auto_ptr(new MathMacroArgument(*this)); -} - - -void MathMacroArgument::write(WriteStream & os) const -{ - os << str_; -} - - -bool MathMacroArgument::metrics(MetricsInfo & mi, Dimension & dim) const -{ - mathed_string_dim(mi.base.font, str_, dim); - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void MathMacroArgument::draw(PainterInfo & pi, int x, int y) const -{ - drawStrRed(pi, x, y, str_); - setPosCache(pi, x, y); -} - - -void MathMacroArgument::normalize(NormalStream & os) const -{ - os << "[macroarg " << str_ << "] "; -} - - -} // namespace lyx diff --git a/src/mathed/MathMacroArgument.cpp b/src/mathed/MathMacroArgument.cpp new file mode 100644 index 0000000000..4d2badb9e0 --- /dev/null +++ b/src/mathed/MathMacroArgument.cpp @@ -0,0 +1,80 @@ +/** + * \file MathMacroArgument.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Alejandro Aguilar Sierra + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "MathMacroArgument.h" +#include "MathStream.h" +#include "MathSupport.h" +#include "debug.h" + + +namespace lyx { + +using std::endl; +using std::auto_ptr; +using std::size_t; +using std::vector; + + +MathMacroArgument::MathMacroArgument(size_t n) + : number_(n) +{ + if (n < 1 || n > 9) { + lyxerr << "MathMacroArgument::MathMacroArgument: wrong Argument id: " + << n << endl; + } + // The profiler tells us not to use + // str_ = '#' + convert(n); + // so we do the conversion of n to ASCII manually. + // This works because 1 <= n <= 9. + str_.resize(2); + str_[0] = '#'; + str_[1] = '0' + n; +} + + +auto_ptr MathMacroArgument::doClone() const +{ + return auto_ptr(new MathMacroArgument(*this)); +} + + +void MathMacroArgument::write(WriteStream & os) const +{ + os << str_; +} + + +bool MathMacroArgument::metrics(MetricsInfo & mi, Dimension & dim) const +{ + mathed_string_dim(mi.base.font, str_, dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void MathMacroArgument::draw(PainterInfo & pi, int x, int y) const +{ + drawStrRed(pi, x, y, str_); + setPosCache(pi, x, y); +} + + +void MathMacroArgument::normalize(NormalStream & os) const +{ + os << "[macroarg " << str_ << "] "; +} + + +} // namespace lyx diff --git a/src/mathed/MathMacroTable.C b/src/mathed/MathMacroTable.C deleted file mode 100644 index 779dc10625..0000000000 --- a/src/mathed/MathMacroTable.C +++ /dev/null @@ -1,124 +0,0 @@ -/** - * \file MathMacroTable.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "MathMacroTable.h" -#include "MathMacroTemplate.h" -#include "MathMacroArgument.h" -#include "MathSupport.h" -#include "InsetMathSqrt.h" - -#include "debug.h" -#include "dociterator.h" - -#include - -#include - - -namespace lyx { - -using std::endl; -using std::istringstream; -using std::map; -using std::pair; -using std::string; -using std::vector; -using std::size_t; - - -MacroData::MacroData() - : numargs_(0), lockCount_(0) -{} - - -MacroData::MacroData(docstring const & def, int numargs, docstring const & disp, string const & requires) - : def_(def), numargs_(numargs), disp_(disp), requires_(requires), lockCount_(0) -{} - - -void MacroData::expand(vector const & args, MathArray & to) const -{ - InsetMathSqrt inset; // Hack. Any inset with a cell would do. - // FIXME UNICODE - asArray(disp_.empty() ? def_ : disp_, inset.cell(0)); - //lyxerr << "MathData::expand: args: " << args << endl; - //lyxerr << "MathData::expand: ar: " << inset.cell(0) << endl; - for (DocIterator it = doc_iterator_begin(inset); it; it.forwardChar()) { - if (!it.nextInset()) - continue; - if (it.nextInset()->lyxCode() != InsetBase::MATHMACROARG_CODE) - continue; - //it.cell().erase(it.pos()); - //it.cell().insert(it.pos(), it.nextInset()->asInsetMath() - size_t n = static_cast(it.nextInset())->number(); - if (n <= args.size()) { - it.cell().erase(it.pos()); - it.cell().insert(it.pos(), args[n - 1]); - } - } - //lyxerr << "MathData::expand: res: " << inset.cell(0) << endl; - to = inset.cell(0); -} - - -// The global table. -MacroTable & MacroTable::globalMacros() -{ - static MacroTable theGlobalMacros; - return theGlobalMacros; -} - - -bool MacroTable::has(docstring const & name) const -{ - return find(name) != end(); -} - - -MacroData const & MacroTable::get(docstring const & name) const -{ - const_iterator it = find(name); - BOOST_ASSERT(it != end()); - return it->second; -} - - -void MacroTable::insert(docstring const & name, MacroData const & data) -{ - //lyxerr << "MacroTable::insert: " << to_utf8(name) << endl; - operator[](name) = data; -} - - -void MacroTable::insert(docstring const & def, string const & requires) -{ - //lyxerr << "MacroTable::insert, def: " << to_utf8(def) << endl; - MathMacroTemplate mac(def); - MacroData data = mac.asMacroData(); - data.requires() = requires; - insert(mac.name(), data); -} - - -void MacroTable::dump() -{ - lyxerr << "\n------------------------------------------" << endl; - for (const_iterator it = begin(); it != end(); ++it) - lyxerr << to_utf8(it->first) - << " [" << to_utf8(it->second.def()) << "] : " - << " [" << to_utf8(it->second.disp()) << "] : " - << endl; - lyxerr << "------------------------------------------" << endl; -} - - -} // namespace lyx diff --git a/src/mathed/MathMacroTable.cpp b/src/mathed/MathMacroTable.cpp new file mode 100644 index 0000000000..779dc10625 --- /dev/null +++ b/src/mathed/MathMacroTable.cpp @@ -0,0 +1,124 @@ +/** + * \file MathMacroTable.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "MathMacroTable.h" +#include "MathMacroTemplate.h" +#include "MathMacroArgument.h" +#include "MathSupport.h" +#include "InsetMathSqrt.h" + +#include "debug.h" +#include "dociterator.h" + +#include + +#include + + +namespace lyx { + +using std::endl; +using std::istringstream; +using std::map; +using std::pair; +using std::string; +using std::vector; +using std::size_t; + + +MacroData::MacroData() + : numargs_(0), lockCount_(0) +{} + + +MacroData::MacroData(docstring const & def, int numargs, docstring const & disp, string const & requires) + : def_(def), numargs_(numargs), disp_(disp), requires_(requires), lockCount_(0) +{} + + +void MacroData::expand(vector const & args, MathArray & to) const +{ + InsetMathSqrt inset; // Hack. Any inset with a cell would do. + // FIXME UNICODE + asArray(disp_.empty() ? def_ : disp_, inset.cell(0)); + //lyxerr << "MathData::expand: args: " << args << endl; + //lyxerr << "MathData::expand: ar: " << inset.cell(0) << endl; + for (DocIterator it = doc_iterator_begin(inset); it; it.forwardChar()) { + if (!it.nextInset()) + continue; + if (it.nextInset()->lyxCode() != InsetBase::MATHMACROARG_CODE) + continue; + //it.cell().erase(it.pos()); + //it.cell().insert(it.pos(), it.nextInset()->asInsetMath() + size_t n = static_cast(it.nextInset())->number(); + if (n <= args.size()) { + it.cell().erase(it.pos()); + it.cell().insert(it.pos(), args[n - 1]); + } + } + //lyxerr << "MathData::expand: res: " << inset.cell(0) << endl; + to = inset.cell(0); +} + + +// The global table. +MacroTable & MacroTable::globalMacros() +{ + static MacroTable theGlobalMacros; + return theGlobalMacros; +} + + +bool MacroTable::has(docstring const & name) const +{ + return find(name) != end(); +} + + +MacroData const & MacroTable::get(docstring const & name) const +{ + const_iterator it = find(name); + BOOST_ASSERT(it != end()); + return it->second; +} + + +void MacroTable::insert(docstring const & name, MacroData const & data) +{ + //lyxerr << "MacroTable::insert: " << to_utf8(name) << endl; + operator[](name) = data; +} + + +void MacroTable::insert(docstring const & def, string const & requires) +{ + //lyxerr << "MacroTable::insert, def: " << to_utf8(def) << endl; + MathMacroTemplate mac(def); + MacroData data = mac.asMacroData(); + data.requires() = requires; + insert(mac.name(), data); +} + + +void MacroTable::dump() +{ + lyxerr << "\n------------------------------------------" << endl; + for (const_iterator it = begin(); it != end(); ++it) + lyxerr << to_utf8(it->first) + << " [" << to_utf8(it->second.def()) << "] : " + << " [" << to_utf8(it->second.disp()) << "] : " + << endl; + lyxerr << "------------------------------------------" << endl; +} + + +} // namespace lyx diff --git a/src/mathed/MathMacroTemplate.C b/src/mathed/MathMacroTemplate.C deleted file mode 100644 index 24cb74a725..0000000000 --- a/src/mathed/MathMacroTemplate.C +++ /dev/null @@ -1,253 +0,0 @@ -/** - * \file math_macrotemplate.C - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "MathMacroTemplate.h" -#include "MathStream.h" -#include "MathParser.h" -#include "MathSupport.h" - -#include "cursor.h" -#include "debug.h" -#include "gettext.h" -#include "lyxlex.h" -#include "LColor.h" - -#include "frontends/FontMetrics.h" -#include "frontends/Painter.h" - -#include "support/lstrings.h" - - -namespace lyx { - -using support::bformat; - -using std::auto_ptr; -using std::ostream; -using std::endl; - - -MathMacroTemplate::MathMacroTemplate() - : InsetMathNest(2), numargs_(0), name_(), type_(from_ascii("newcommand")) -{ - initMath(); -} - - -MathMacroTemplate::MathMacroTemplate(docstring const & name, int numargs, - docstring const & type, MathArray const & ar1, MathArray const & ar2) - : InsetMathNest(2), numargs_(numargs), name_(name), type_(type) -{ - initMath(); - - if (numargs_ > 9) - lyxerr << "MathMacroTemplate::MathMacroTemplate: wrong # of arguments: " - << numargs_ << std::endl; - cell(0) = ar1; - cell(1) = ar2; -} - - -MathMacroTemplate::MathMacroTemplate(docstring const & str) - : InsetMathNest(2), numargs_(0), name_() -{ - initMath(); - - MathArray ar; - mathed_parse_cell(ar, str); - if (ar.size() != 1 || !ar[0]->asMacroTemplate()) { - lyxerr << "Cannot read macro from '" << ar << "'" << endl; - return; - } - operator=( *(ar[0]->asMacroTemplate()) ); -} - - -auto_ptr MathMacroTemplate::doClone() const -{ - return auto_ptr(new MathMacroTemplate(*this)); -} - - -void MathMacroTemplate::edit(LCursor & cur, bool) -{ - //lyxerr << "MathMacroTemplate: edit left/right" << endl; - cur.push(*this); -} - - -int MathMacroTemplate::numargs() const -{ - return numargs_; -} - - -void MathMacroTemplate::numargs(int numargs) -{ - numargs_ = numargs; -} - - -docstring MathMacroTemplate::name() const -{ - return name_; -} - - -docstring MathMacroTemplate::prefix() const -{ - return bformat(_(" Macro: %1$s: "), name_); -} - - -bool MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const -{ - bool lockMacro = MacroTable::globalMacros().has(name_); - if (lockMacro) - MacroTable::globalMacros().get(name_).lock(); - - cell(0).metrics(mi); - cell(1).metrics(mi); - docstring dp = prefix(); - dim.wid = cell(0).width() + cell(1).width() + 20 - + theFontMetrics(mi.base.font).width(dp); - dim.asc = std::max(cell(0).ascent(), cell(1).ascent()) + 7; - dim.des = std::max(cell(0).descent(), cell(1).descent()) + 7; - - if (lockMacro) - MacroTable::globalMacros().get(name_).unlock(); - - if (dim_ == dim) - return false; - dim_ = dim; - return true; -} - - -void MathMacroTemplate::draw(PainterInfo & p, int x, int y) const -{ - bool lockMacro = MacroTable::globalMacros().has(name_); - if (lockMacro) - MacroTable::globalMacros().get(name_).lock(); - - setPosCache(p, x, y); - - // label - LyXFont font = p.base.font; - font.setColor(LColor::math); - - PainterInfo pi(p.base.bv, p.pain); - pi.base.style = LM_ST_TEXT; - pi.base.font = font; - - int const a = y - dim_.asc + 1; - int const w = dim_.wid - 2; - int const h = dim_.height() - 2; - - // LColor::mathbg used to be "AntiqueWhite" but is "linen" now, too - // the next line would overwrite the selection! - //pi.pain.fillRectangle(x, a, w, h, LColor::mathmacrobg); - pi.pain.rectangle(x, a, w, h, LColor::mathframe); - -#ifdef WITH_WARNINGS -#warning FIXME -#endif -#if 0 - LCursor & cur = p.base.bv->cursor(); - if (cur.isInside(this)) - cur.drawSelection(pi); -#endif - docstring dp = prefix(); - pi.pain.text(x + 2, y, dp, font); - // FIXME: Painter text should retain the drawn text width - x += theFontMetrics(font).width(dp) + 6; - - int const w0 = cell(0).width(); - int const w1 = cell(1).width(); - cell(0).draw(pi, x + 2, y + 1); - pi.pain.rectangle(x, y - dim_.ascent() + 3, - w0 + 4, dim_.height() - 6, LColor::mathline); - cell(1).draw(pi, x + 8 + w0, y + 1); - pi.pain.rectangle(x + w0 + 6, y - dim_.ascent() + 3, - w1 + 4, dim_.height() - 6, LColor::mathline); - - if (lockMacro) - MacroTable::globalMacros().get(name_).unlock(); -} - - -void MathMacroTemplate::read(Buffer const &, LyXLex & lex) -{ - MathArray ar; - mathed_parse_cell(ar, lex.getStream()); - if (ar.size() != 1 || !ar[0]->asMacroTemplate()) { - lyxerr << "Cannot read macro from '" << ar << "'" << endl; - lyxerr << "Read: " << to_utf8(asString(ar)) << endl; - return; - } - operator=( *(ar[0]->asMacroTemplate()) ); -} - - -void MathMacroTemplate::write(Buffer const &, std::ostream & os) const -{ - odocstringstream oss; - WriteStream wi(oss, false, false); - oss << "FormulaMacro\n"; - write(wi); - os << to_utf8(oss.str()); -} - - -void MathMacroTemplate::write(WriteStream & os) const -{ - if (type_ == "def") { - os << "\\def\\" << name_.c_str(); - for (int i = 1; i <= numargs_; ++i) - os << '#' << i; - } else { - // newcommand or renewcommand - os << "\\" << type_.c_str() << "{\\" << name_.c_str() << '}'; - if (numargs_ > 0) - os << '[' << numargs_ << ']'; - } - - os << '{' << cell(0) << "}"; - - if (os.latex()) { - // writing .tex. done. - os << "\n"; - } else { - // writing .lyx, write special .tex export only if necessary - if (!cell(1).empty()) - os << "\n{" << cell(1) << '}'; - } -} - - -int MathMacroTemplate::plaintext(Buffer const &, odocstream & os, - OutputParams const &) const -{ - static docstring const str = '[' + _("math macro") + ']'; - - os << str; - return str.size(); -} - - -MacroData MathMacroTemplate::asMacroData() const -{ - return MacroData(asString(cell(0)), numargs(), asString(cell(1)), std::string()); -} - - -} // namespace lyx diff --git a/src/mathed/MathMacroTemplate.cpp b/src/mathed/MathMacroTemplate.cpp new file mode 100644 index 0000000000..24cb74a725 --- /dev/null +++ b/src/mathed/MathMacroTemplate.cpp @@ -0,0 +1,253 @@ +/** + * \file math_macrotemplate.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "MathMacroTemplate.h" +#include "MathStream.h" +#include "MathParser.h" +#include "MathSupport.h" + +#include "cursor.h" +#include "debug.h" +#include "gettext.h" +#include "lyxlex.h" +#include "LColor.h" + +#include "frontends/FontMetrics.h" +#include "frontends/Painter.h" + +#include "support/lstrings.h" + + +namespace lyx { + +using support::bformat; + +using std::auto_ptr; +using std::ostream; +using std::endl; + + +MathMacroTemplate::MathMacroTemplate() + : InsetMathNest(2), numargs_(0), name_(), type_(from_ascii("newcommand")) +{ + initMath(); +} + + +MathMacroTemplate::MathMacroTemplate(docstring const & name, int numargs, + docstring const & type, MathArray const & ar1, MathArray const & ar2) + : InsetMathNest(2), numargs_(numargs), name_(name), type_(type) +{ + initMath(); + + if (numargs_ > 9) + lyxerr << "MathMacroTemplate::MathMacroTemplate: wrong # of arguments: " + << numargs_ << std::endl; + cell(0) = ar1; + cell(1) = ar2; +} + + +MathMacroTemplate::MathMacroTemplate(docstring const & str) + : InsetMathNest(2), numargs_(0), name_() +{ + initMath(); + + MathArray ar; + mathed_parse_cell(ar, str); + if (ar.size() != 1 || !ar[0]->asMacroTemplate()) { + lyxerr << "Cannot read macro from '" << ar << "'" << endl; + return; + } + operator=( *(ar[0]->asMacroTemplate()) ); +} + + +auto_ptr MathMacroTemplate::doClone() const +{ + return auto_ptr(new MathMacroTemplate(*this)); +} + + +void MathMacroTemplate::edit(LCursor & cur, bool) +{ + //lyxerr << "MathMacroTemplate: edit left/right" << endl; + cur.push(*this); +} + + +int MathMacroTemplate::numargs() const +{ + return numargs_; +} + + +void MathMacroTemplate::numargs(int numargs) +{ + numargs_ = numargs; +} + + +docstring MathMacroTemplate::name() const +{ + return name_; +} + + +docstring MathMacroTemplate::prefix() const +{ + return bformat(_(" Macro: %1$s: "), name_); +} + + +bool MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const +{ + bool lockMacro = MacroTable::globalMacros().has(name_); + if (lockMacro) + MacroTable::globalMacros().get(name_).lock(); + + cell(0).metrics(mi); + cell(1).metrics(mi); + docstring dp = prefix(); + dim.wid = cell(0).width() + cell(1).width() + 20 + + theFontMetrics(mi.base.font).width(dp); + dim.asc = std::max(cell(0).ascent(), cell(1).ascent()) + 7; + dim.des = std::max(cell(0).descent(), cell(1).descent()) + 7; + + if (lockMacro) + MacroTable::globalMacros().get(name_).unlock(); + + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void MathMacroTemplate::draw(PainterInfo & p, int x, int y) const +{ + bool lockMacro = MacroTable::globalMacros().has(name_); + if (lockMacro) + MacroTable::globalMacros().get(name_).lock(); + + setPosCache(p, x, y); + + // label + LyXFont font = p.base.font; + font.setColor(LColor::math); + + PainterInfo pi(p.base.bv, p.pain); + pi.base.style = LM_ST_TEXT; + pi.base.font = font; + + int const a = y - dim_.asc + 1; + int const w = dim_.wid - 2; + int const h = dim_.height() - 2; + + // LColor::mathbg used to be "AntiqueWhite" but is "linen" now, too + // the next line would overwrite the selection! + //pi.pain.fillRectangle(x, a, w, h, LColor::mathmacrobg); + pi.pain.rectangle(x, a, w, h, LColor::mathframe); + +#ifdef WITH_WARNINGS +#warning FIXME +#endif +#if 0 + LCursor & cur = p.base.bv->cursor(); + if (cur.isInside(this)) + cur.drawSelection(pi); +#endif + docstring dp = prefix(); + pi.pain.text(x + 2, y, dp, font); + // FIXME: Painter text should retain the drawn text width + x += theFontMetrics(font).width(dp) + 6; + + int const w0 = cell(0).width(); + int const w1 = cell(1).width(); + cell(0).draw(pi, x + 2, y + 1); + pi.pain.rectangle(x, y - dim_.ascent() + 3, + w0 + 4, dim_.height() - 6, LColor::mathline); + cell(1).draw(pi, x + 8 + w0, y + 1); + pi.pain.rectangle(x + w0 + 6, y - dim_.ascent() + 3, + w1 + 4, dim_.height() - 6, LColor::mathline); + + if (lockMacro) + MacroTable::globalMacros().get(name_).unlock(); +} + + +void MathMacroTemplate::read(Buffer const &, LyXLex & lex) +{ + MathArray ar; + mathed_parse_cell(ar, lex.getStream()); + if (ar.size() != 1 || !ar[0]->asMacroTemplate()) { + lyxerr << "Cannot read macro from '" << ar << "'" << endl; + lyxerr << "Read: " << to_utf8(asString(ar)) << endl; + return; + } + operator=( *(ar[0]->asMacroTemplate()) ); +} + + +void MathMacroTemplate::write(Buffer const &, std::ostream & os) const +{ + odocstringstream oss; + WriteStream wi(oss, false, false); + oss << "FormulaMacro\n"; + write(wi); + os << to_utf8(oss.str()); +} + + +void MathMacroTemplate::write(WriteStream & os) const +{ + if (type_ == "def") { + os << "\\def\\" << name_.c_str(); + for (int i = 1; i <= numargs_; ++i) + os << '#' << i; + } else { + // newcommand or renewcommand + os << "\\" << type_.c_str() << "{\\" << name_.c_str() << '}'; + if (numargs_ > 0) + os << '[' << numargs_ << ']'; + } + + os << '{' << cell(0) << "}"; + + if (os.latex()) { + // writing .tex. done. + os << "\n"; + } else { + // writing .lyx, write special .tex export only if necessary + if (!cell(1).empty()) + os << "\n{" << cell(1) << '}'; + } +} + + +int MathMacroTemplate::plaintext(Buffer const &, odocstream & os, + OutputParams const &) const +{ + static docstring const str = '[' + _("math macro") + ']'; + + os << str; + return str.size(); +} + + +MacroData MathMacroTemplate::asMacroData() const +{ + return MacroData(asString(cell(0)), numargs(), asString(cell(1)), std::string()); +} + + +} // namespace lyx diff --git a/src/mathed/MathParser.C b/src/mathed/MathParser.C deleted file mode 100644 index c985057b99..0000000000 --- a/src/mathed/MathParser.C +++ /dev/null @@ -1,1511 +0,0 @@ -/** - * \file MathParser.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -/* - -If someone desperately needs partial "structures" (such as a few -cells of an array inset or similar) (s)he could uses the -following hack as starting point to write some macros: - - \newif\ifcomment - \commentfalse - \ifcomment - \def\makeamptab{\catcode`\&=4\relax} - \def\makeampletter{\catcode`\&=11\relax} - \def\b{\makeampletter\expandafter\makeamptab\bi} - \long\def\bi#1\e{} - \else - \def\b{}\def\e{} - \fi - - ... - - \[\begin{array}{ccc} -1 -& - - \end{array}\] - -*/ - - -#include - -#include "MathParser.h" - -#include "InsetMathArray.h" -#include "InsetMathBig.h" -#include "InsetMathBrace.h" -#include "InsetMathChar.h" -#include "InsetMathColor.h" -#include "InsetMathComment.h" -#include "InsetMathDelim.h" -#include "InsetMathEnv.h" -#include "InsetMathKern.h" -#include "InsetMathMacro.h" -#include "InsetMathPar.h" -#include "InsetMathRef.h" -#include "InsetMathRoot.h" -#include "InsetMathScript.h" -#include "InsetMathSplit.h" -#include "InsetMathSqrt.h" -#include "InsetMathTabular.h" -#include "MathMacroTemplate.h" -#include "MathFactory.h" -#include "MathMacroArgument.h" -#include "MathSupport.h" - -#include "lyxlex.h" -#include "debug.h" - -#include "support/convert.h" - -#include - - -namespace lyx { - -using std::endl; -using std::fill; - -using std::string; -using std::ios; -using std::istream; -using std::ostream; -using std::vector; - - -//#define FILEDEBUG - - -namespace { - -InsetMath::mode_type asMode(InsetMath::mode_type oldmode, docstring const & str) -{ - //lyxerr << "handling mode: '" << str << "'" << endl; - if (str == "mathmode") - return InsetMath::MATH_MODE; - if (str == "textmode" || str == "forcetext") - return InsetMath::TEXT_MODE; - return oldmode; -} - - -bool stared(docstring const & s) -{ - size_t const n = s.size(); - return n && s[n - 1] == '*'; -} - - -/*! - * Add the row \p cellrow to \p grid. - * \returns wether the row could be added. Adding a row can fail for - * environments like "equation" that have a fixed number of rows. - */ -bool addRow(InsetMathGrid & grid, InsetMathGrid::row_type & cellrow, - docstring const & vskip, bool allow_pagebreak = true) -{ - ++cellrow; - if (cellrow == grid.nrows()) { - //lyxerr << "adding row " << cellrow << endl; - grid.addRow(cellrow - 1); - if (cellrow == grid.nrows()) { - // We can't add a row to this grid, so let's - // append the content of this cell to the previous - // one. - // This does not happen in well formed .lyx files, - // but LyX versions 1.3.x and older could create - // such files and tex2lyx can still do that. - --cellrow; - lyxerr << "ignoring extra row"; - if (!vskip.empty()) - lyxerr << " with extra space " << to_utf8(vskip); - if (!allow_pagebreak) - lyxerr << " with no page break allowed"; - lyxerr << '.' << endl; - return false; - } - } - grid.vcrskip(LyXLength(to_utf8(vskip)), cellrow - 1); - grid.rowinfo(cellrow - 1).allow_pagebreak_ = allow_pagebreak; - return true; -} - - -/*! - * Add the column \p cellcol to \p grid. - * \returns wether the column could be added. Adding a column can fail for - * environments like "eqnarray" that have a fixed number of columns. - */ -bool addCol(InsetMathGrid & grid, InsetMathGrid::col_type & cellcol) -{ - ++cellcol; - if (cellcol == grid.ncols()) { - //lyxerr << "adding column " << cellcol << endl; - grid.addCol(cellcol - 1); - if (cellcol == grid.ncols()) { - // We can't add a column to this grid, so let's - // append the content of this cell to the previous - // one. - // This does not happen in well formed .lyx files, - // but LyX versions 1.3.x and older could create - // such files and tex2lyx can still do that. - --cellcol; - lyxerr << "ignoring extra column." << endl; - return false; - } - } - return true; -} - - -/*! - * Check wether the last row is empty and remove it if yes. - * Otherwise the following code - * \verbatim -\begin{array}{|c|c|} -\hline -1 & 2 \\ \hline -3 & 4 \\ \hline -\end{array} - * \endverbatim - * will result in a grid with 3 rows (+ the dummy row that is always present), - * because the last '\\' opens a new row. - */ -void delEmptyLastRow(InsetMathGrid & grid) -{ - InsetMathGrid::row_type const row = grid.nrows() - 1; - for (InsetMathGrid::col_type col = 0; col < grid.ncols(); ++col) { - if (!grid.cell(grid.index(row, col)).empty()) - return; - } - // Copy the row information of the empty row (which would contain the - // last hline in the example above) to the dummy row and delete the - // empty row. - grid.rowinfo(row + 1) = grid.rowinfo(row); - grid.delRow(row); -} - - -// These are TeX's catcodes -enum CatCode { - catEscape, // 0 backslash - catBegin, // 1 { - catEnd, // 2 } - catMath, // 3 $ - catAlign, // 4 & - catNewline, // 5 ^^M - catParameter, // 6 # - catSuper, // 7 ^ - catSub, // 8 _ - catIgnore, // 9 - catSpace, // 10 space - catLetter, // 11 a-zA-Z - catOther, // 12 none of the above - catActive, // 13 ~ - catComment, // 14 % - catInvalid // 15 -}; - -CatCode theCatcode[128]; - - -inline CatCode catcode(char_type c) -{ - /* The only characters that are not catOther lie in the pure ASCII - * range. Therefore theCatcode has only 128 entries. - * TeX itself deals with 8bit characters, so if needed this table - * could be enlarged to 256 entries. - * Any larger value does not make sense, since the fact that we use - * unicode internally does not change Knuth's TeX engine. - * Apart from that a table for the full 21bit UCS4 range would waste - * too much memory. */ - if (c >= 128) - return catOther; - - return theCatcode[c]; -} - - -enum { - FLAG_ALIGN = 1 << 0, // next & or \\ ends the parsing process - FLAG_BRACE_LAST = 1 << 1, // next closing brace ends the parsing - FLAG_RIGHT = 1 << 2, // next \\right ends the parsing process - FLAG_END = 1 << 3, // next \\end ends the parsing process - FLAG_BRACK_LAST = 1 << 4, // next closing bracket ends the parsing - FLAG_TEXTMODE = 1 << 5, // we are in a box - FLAG_ITEM = 1 << 6, // read a (possibly braced token) - FLAG_LEAVE = 1 << 7, // leave the loop at the end - FLAG_SIMPLE = 1 << 8, // next $ leaves the loop - FLAG_EQUATION = 1 << 9, // next \] leaves the loop - FLAG_SIMPLE2 = 1 << 10, // next \) leaves the loop - FLAG_OPTION = 1 << 11, // read [...] style option - FLAG_BRACED = 1 << 12 // read {...} style argument -}; - - -// -// Helper class for parsing -// - -class Token { -public: - /// - Token() : cs_(), char_(0), cat_(catIgnore) {} - /// - Token(char_type c, CatCode cat) : cs_(), char_(c), cat_(cat) {} - /// - explicit Token(docstring const & cs) : cs_(cs), char_(0), cat_(catIgnore) {} - - /// - docstring const & cs() const { return cs_; } - /// - CatCode cat() const { return cat_; } - /// - char_type character() const { return char_; } - /// - docstring asString() const { return cs_.size() ? cs_ : docstring(1, char_); } - /// - docstring asInput() const { return cs_.size() ? '\\' + cs_ : docstring(1, char_); } - -private: - /// - docstring cs_; - /// - char_type char_; - /// - CatCode cat_; -}; - - -ostream & operator<<(ostream & os, Token const & t) -{ - if (t.cs().size()) { - docstring const & cs = t.cs(); - // FIXME: For some strange reason, the stream operator instanciate - // a new Token before outputting the contents of t.cs(). - // Because of this the line - // os << '\\' << cs; - // below becomes recursive. - // In order to avoid that we return early: - if (cs == "\\") - return os; - os << '\\' << to_utf8(cs); - } - else if (t.cat() == catLetter) - os << t.character(); - else - os << '[' << t.character() << ',' << t.cat() << ']'; - return os; -} - - -class Parser { -public: - /// - typedef InsetMath::mode_type mode_type; - - /// - Parser(LyXLex & lex); - /// Only use this for reading from .lyx file format, for the reason - /// see Parser::tokenize(std::istream &). - Parser(istream & is); - /// - Parser(docstring const & str); - - /// - bool parse(MathAtom & at); - /// - void parse(MathArray & array, unsigned flags, mode_type mode); - /// - void parse1(InsetMathGrid & grid, unsigned flags, mode_type mode, - bool numbered); - /// - MathArray parse(unsigned flags, mode_type mode); - /// - int lineno() const { return lineno_; } - /// - void putback(); - -private: - /// - void parse2(MathAtom & at, unsigned flags, mode_type mode, bool numbered); - /// get arg delimited by 'left' and 'right' - docstring getArg(char_type left, char_type right); - /// - char_type getChar(); - /// - void error(string const & msg); - void error(docstring const & msg) { error(to_utf8(msg)); } - /// dump contents to screen - void dump() const; - /// Only use this for reading from .lyx file format (see - /// implementation for reason) - void tokenize(istream & is); - /// - void tokenize(docstring const & s); - /// - void skipSpaceTokens(idocstream & is, char_type c); - /// - void push_back(Token const & t); - /// - void pop_back(); - /// - Token const & prevToken() const; - /// - Token const & nextToken() const; - /// - Token const & getToken(); - /// skips spaces if any - void skipSpaces(); - /// - void lex(docstring const & s); - /// - bool good() const; - /// - docstring parse_verbatim_item(); - /// - docstring parse_verbatim_option(); - - /// - int lineno_; - /// - vector tokens_; - /// - unsigned pos_; - /// Stack of active environments - vector environments_; -}; - - -Parser::Parser(LyXLex & lexer) - : lineno_(lexer.getLineNo()), pos_(0) -{ - tokenize(lexer.getStream()); - lexer.eatLine(); -} - - -Parser::Parser(istream & is) - : lineno_(0), pos_(0) -{ - tokenize(is); -} - - -Parser::Parser(docstring const & str) - : lineno_(0), pos_(0) -{ - tokenize(str); -} - - -void Parser::push_back(Token const & t) -{ - tokens_.push_back(t); -} - - -void Parser::pop_back() -{ - tokens_.pop_back(); -} - - -Token const & Parser::prevToken() const -{ - static const Token dummy; - return pos_ > 0 ? tokens_[pos_ - 1] : dummy; -} - - -Token const & Parser::nextToken() const -{ - static const Token dummy; - return good() ? tokens_[pos_] : dummy; -} - - -Token const & Parser::getToken() -{ - static const Token dummy; - //lyxerr << "looking at token " << tokens_[pos_] << " pos: " << pos_ << endl; - return good() ? tokens_[pos_++] : dummy; -} - - -void Parser::skipSpaces() -{ - while (nextToken().cat() == catSpace || nextToken().cat() == catNewline) - getToken(); -} - - -void Parser::putback() -{ - --pos_; -} - - -bool Parser::good() const -{ - return pos_ < tokens_.size(); -} - - -char_type Parser::getChar() -{ - if (!good()) - error("The input stream is not well..."); - return tokens_[pos_++].character(); -} - - -docstring Parser::getArg(char_type left, char_type right) -{ - skipSpaces(); - - docstring result; - char_type c = getChar(); - - if (c != left) - putback(); - else - while ((c = getChar()) != right && good()) - result += c; - - return result; -} - - -void Parser::skipSpaceTokens(idocstream & is, char_type c) -{ - // skip trailing spaces - while (catcode(c) == catSpace || catcode(c) == catNewline) - if (!is.get(c)) - break; - //lyxerr << "putting back: " << c << endl; - is.putback(c); -} - - -void Parser::tokenize(istream & is) -{ - // eat everything up to the next \end_inset or end of stream - // and store it in s for further tokenization - string s; - char c; - while (is.get(c)) { - s += c; - if (s.size() >= 10 && s.substr(s.size() - 10) == "\\end_inset") { - s = s.substr(0, s.size() - 10); - break; - } - } - // Remove the space after \end_inset - if (is.get(c) && c != ' ') - is.unget(); - - // tokenize buffer - tokenize(from_utf8(s)); -} - - -void Parser::tokenize(docstring const & buffer) -{ - idocstringstream is(buffer, ios::in | ios::binary); - - char_type c; - while (is.get(c)) { - //lyxerr << "reading c: " << c << endl; - - switch (catcode(c)) { - case catNewline: { - ++lineno_; - is.get(c); - if (catcode(c) == catNewline) - ; //push_back(Token("par")); - else { - push_back(Token('\n', catNewline)); - is.putback(c); - } - break; - } - -/* - case catComment: { - while (is.get(c) && catcode(c) != catNewline) - ; - ++lineno_; - break; - } -*/ - - case catEscape: { - is.get(c); - if (!is) { - error("unexpected end of input"); - } else { - docstring s(1, c); - if (catcode(c) == catLetter) { - // collect letters - while (is.get(c) && catcode(c) == catLetter) - s += c; - skipSpaceTokens(is, c); - } - push_back(Token(s)); - } - break; - } - - case catSuper: - case catSub: { - push_back(Token(c, catcode(c))); - is.get(c); - skipSpaceTokens(is, c); - break; - } - - case catIgnore: { - lyxerr << "ignoring a char: " << int(c) << endl; - break; - } - - default: - push_back(Token(c, catcode(c))); - } - } - -#ifdef FILEDEBUG - dump(); -#endif -} - - -void Parser::dump() const -{ - lyxerr << "\nTokens: "; - for (unsigned i = 0; i < tokens_.size(); ++i) { - if (i == pos_) - lyxerr << " <#> "; - lyxerr << tokens_[i]; - } - lyxerr << " pos: " << pos_ << endl; -} - - -void Parser::error(string const & msg) -{ - lyxerr << "Line ~" << lineno_ << ": Math parse error: " << msg << endl; - dump(); - //exit(1); -} - - -bool Parser::parse(MathAtom & at) -{ - skipSpaces(); - MathArray ar; - parse(ar, false, InsetMath::UNDECIDED_MODE); - if (ar.size() != 1 || ar.front()->getType() == hullNone) { - lyxerr << "unusual contents found: " << ar << endl; - at = MathAtom(new InsetMathPar(ar)); - //if (at->nargs() > 0) - // at.nucleus()->cell(0) = ar; - //else - // lyxerr << "unusual contents found: " << ar << endl; - return true; - } - at = ar[0]; - return true; -} - - -docstring Parser::parse_verbatim_option() -{ - skipSpaces(); - docstring res; - if (nextToken().character() == '[') { - Token t = getToken(); - for (Token t = getToken(); t.character() != ']' && good(); t = getToken()) { - if (t.cat() == catBegin) { - putback(); - res += '{' + parse_verbatim_item() + '}'; - } else - res += t.asString(); - } - } - return res; -} - - -docstring Parser::parse_verbatim_item() -{ - skipSpaces(); - docstring res; - if (nextToken().cat() == catBegin) { - Token t = getToken(); - for (Token t = getToken(); t.cat() != catEnd && good(); t = getToken()) { - if (t.cat() == catBegin) { - putback(); - res += '{' + parse_verbatim_item() + '}'; - } - else - res += t.asString(); - } - } - return res; -} - - -MathArray Parser::parse(unsigned flags, mode_type mode) -{ - MathArray ar; - parse(ar, flags, mode); - return ar; -} - - -void Parser::parse(MathArray & array, unsigned flags, mode_type mode) -{ - InsetMathGrid grid(1, 1); - parse1(grid, flags, mode, false); - array = grid.cell(0); -} - - -void Parser::parse2(MathAtom & at, const unsigned flags, const mode_type mode, - const bool numbered) -{ - parse1(*(at.nucleus()->asGridInset()), flags, mode, numbered); -} - - -void Parser::parse1(InsetMathGrid & grid, unsigned flags, - const mode_type mode, const bool numbered) -{ - int limits = 0; - InsetMathGrid::row_type cellrow = 0; - InsetMathGrid::col_type cellcol = 0; - MathArray * cell = &grid.cell(grid.index(cellrow, cellcol)); - - if (grid.asHullInset()) - grid.asHullInset()->numbered(cellrow, numbered); - - //dump(); - //lyxerr << " flags: " << flags << endl; - //lyxerr << " mode: " << mode << endl; - //lyxerr << "grid: " << grid << endl; - - while (good()) { - Token const & t = getToken(); - -#ifdef FILEDEBUG - lyxerr << "t: " << t << " flags: " << flags << endl; - lyxerr << "mode: " << mode << endl; - cell->dump(); - lyxerr << endl; -#endif - - if (flags & FLAG_ITEM) { - - if (t.cat() == catBegin) { - // skip the brace and collect everything to the next matching - // closing brace - parse1(grid, FLAG_BRACE_LAST, mode, numbered); - return; - } - - // handle only this single token, leave the loop if done - flags = FLAG_LEAVE; - } - - - if (flags & FLAG_BRACED) { - if (t.cat() == catSpace) - continue; - - if (t.cat() != catBegin) { - error("opening brace expected"); - return; - } - - // skip the brace and collect everything to the next matching - // closing brace - flags = FLAG_BRACE_LAST; - } - - - if (flags & FLAG_OPTION) { - if (t.cat() == catOther && t.character() == '[') { - MathArray ar; - parse(ar, FLAG_BRACK_LAST, mode); - cell->append(ar); - } else { - // no option found, put back token and we are done - putback(); - } - return; - } - - // - // cat codes - // - if (t.cat() == catMath) { - if (mode != InsetMath::MATH_MODE) { - // we are inside some text mode thingy, so opening new math is allowed - Token const & n = getToken(); - if (n.cat() == catMath) { - // TeX's $$...$$ syntax for displayed math - cell->push_back(MathAtom(new InsetMathHull(hullEquation))); - parse2(cell->back(), FLAG_SIMPLE, InsetMath::MATH_MODE, false); - getToken(); // skip the second '$' token - } else { - // simple $...$ stuff - putback(); - cell->push_back(MathAtom(new InsetMathHull(hullSimple))); - parse2(cell->back(), FLAG_SIMPLE, InsetMath::MATH_MODE, false); - } - } - - else if (flags & FLAG_SIMPLE) { - // this is the end of the formula - return; - } - - else { - error("something strange in the parser"); - break; - } - } - - else if (t.cat() == catLetter) - cell->push_back(MathAtom(new InsetMathChar(t.character()))); - - else if (t.cat() == catSpace && mode != InsetMath::MATH_MODE) { - if (cell->empty() || cell->back()->getChar() != ' ') - cell->push_back(MathAtom(new InsetMathChar(t.character()))); - } - - else if (t.cat() == catNewline && mode != InsetMath::MATH_MODE) { - if (cell->empty() || cell->back()->getChar() != ' ') - cell->push_back(MathAtom(new InsetMathChar(' '))); - } - - else if (t.cat() == catParameter) { - Token const & n = getToken(); - cell->push_back(MathAtom(new MathMacroArgument(n.character()-'0'))); - } - - else if (t.cat() == catActive) - cell->push_back(MathAtom(new InsetMathChar(t.character()))); - - else if (t.cat() == catBegin) { - MathArray ar; - parse(ar, FLAG_BRACE_LAST, mode); - // do not create a BraceInset if they were written by LyX - // this helps to keep the annoyance of "a choose b" to a minimum - if (ar.size() == 1 && ar[0]->extraBraces()) - cell->append(ar); - else - cell->push_back(MathAtom(new InsetMathBrace(ar))); - } - - else if (t.cat() == catEnd) { - if (flags & FLAG_BRACE_LAST) - return; - error("found '}' unexpectedly"); - //BOOST_ASSERT(false); - //add(cell, '}', LM_TC_TEX); - } - - else if (t.cat() == catAlign) { - //lyxerr << " column now " << (cellcol + 1) - // << " max: " << grid.ncols() << endl; - if (flags & FLAG_ALIGN) - return; - if (addCol(grid, cellcol)) - cell = &grid.cell(grid.index(cellrow, cellcol)); - } - - else if (t.cat() == catSuper || t.cat() == catSub) { - bool up = (t.cat() == catSuper); - // we need no new script inset if the last thing was a scriptinset, - // which has that script already not the same script already - if (!cell->size()) - cell->push_back(MathAtom(new InsetMathScript(up))); - else if (cell->back()->asScriptInset() && - !cell->back()->asScriptInset()->has(up)) - cell->back().nucleus()->asScriptInset()->ensure(up); - else if (cell->back()->asScriptInset()) - cell->push_back(MathAtom(new InsetMathScript(up))); - else - cell->back() = MathAtom(new InsetMathScript(cell->back(), up)); - InsetMathScript * p = cell->back().nucleus()->asScriptInset(); - // special handling of {}-bases - // Here we could remove the brace inset for things - // like {a'}^2 and add the braces back in - // InsetMathScript::write(). - // We do not do it, since it is not possible to detect - // reliably whether the braces are needed because the - // nucleus contains more than one symbol, or whether - // they are needed for unknown commands like \xx{a}_0 - // or \yy{a}{b}_0. This was done in revision 14819 - // in an unreliable way. See this thread - // http://www.mail-archive.com/lyx-devel%40lists.lyx.org/msg104917.html - // for more details. - parse(p->cell(p->idxOfScript(up)), FLAG_ITEM, mode); - if (limits) { - p->limits(limits); - limits = 0; - } - } - - else if (t.character() == ']' && (flags & FLAG_BRACK_LAST)) { - //lyxerr << "finished reading option" << endl; - return; - } - - else if (t.cat() == catOther) - cell->push_back(MathAtom(new InsetMathChar(t.character()))); - - else if (t.cat() == catComment) { - docstring s; - while (good()) { - Token const & t = getToken(); - if (t.cat() == catNewline) - break; - s += t.asString(); - } - cell->push_back(MathAtom(new InsetMathComment(s))); - skipSpaces(); - } - - // - // control sequences - // - - else if (t.cs() == "lyxlock") { - if (cell->size()) - cell->back().nucleus()->lock(true); - } - - else if (t.cs() == "def" || - t.cs() == "newcommand" || - t.cs() == "renewcommand") - { - docstring const type = t.cs(); - docstring name; - int nargs = 0; - if (t.cs() == "def") { - // get name - name = getToken().cs(); - - // read parameter - docstring pars; - while (good() && nextToken().cat() != catBegin) { - pars += getToken().cs(); - ++nargs; - } - nargs /= 2; - //lyxerr << "read \\def parameter list '" << pars << "'" << endl; - - } else { // t.cs() == "newcommand" || t.cs() == "renewcommand" - - if (getToken().cat() != catBegin) { - error("'{' in \\newcommand expected (1) "); - return; - } - - name = getToken().cs(); - - if (getToken().cat() != catEnd) { - error("'}' in \\newcommand expected"); - return; - } - - docstring const arg = getArg('[', ']'); - if (!arg.empty()) - nargs = convert(arg); - - } - - MathArray ar1; - parse(ar1, FLAG_ITEM, InsetMath::UNDECIDED_MODE); - - // we cannot handle recursive stuff at all - //MathArray test; - //test.push_back(createInsetMath(name)); - //if (ar1.contains(test)) { - // error("we cannot handle recursive macros at all."); - // return; - //} - - // is a version for display attached? - skipSpaces(); - MathArray ar2; - if (nextToken().cat() == catBegin) - parse(ar2, FLAG_ITEM, InsetMath::MATH_MODE); - - cell->push_back(MathAtom(new MathMacroTemplate(name, nargs, type, - ar1, ar2))); - } - - else if (t.cs() == "(") { - cell->push_back(MathAtom(new InsetMathHull(hullSimple))); - parse2(cell->back(), FLAG_SIMPLE2, InsetMath::MATH_MODE, false); - } - - else if (t.cs() == "[") { - cell->push_back(MathAtom(new InsetMathHull(hullEquation))); - parse2(cell->back(), FLAG_EQUATION, InsetMath::MATH_MODE, false); - } - - else if (t.cs() == "protect") - // ignore \\protect, will hopefully be re-added during output - ; - - else if (t.cs() == "end") { - if (flags & FLAG_END) { - // eat environment name - docstring const name = getArg('{', '}'); - if (environments_.empty()) - error("'found \\end{" + name + - "}' without matching '\\begin{" + - name + "}'"); - else if (name != environments_.back()) - error("'\\end{" + name + - "}' does not match '\\begin{" + - environments_.back() + "}'"); - else { - environments_.pop_back(); - // Delete empty last row in matrix - // like insets. - // If you abuse InsetMathGrid for - // non-matrix like structures you - // probably need to refine this test. - // Right now we only have to test for - // single line hull insets. - if (grid.nrows() > 1) - delEmptyLastRow(grid); - return; - } - } else - error("found 'end' unexpectedly"); - } - - else if (t.cs() == ")") { - if (flags & FLAG_SIMPLE2) - return; - error("found '\\)' unexpectedly"); - } - - else if (t.cs() == "]") { - if (flags & FLAG_EQUATION) - return; - error("found '\\]' unexpectedly"); - } - - else if (t.cs() == "\\") { - if (flags & FLAG_ALIGN) - return; - bool added; - if (nextToken().asInput() == "*") { - getToken(); - added = addRow(grid, cellrow, docstring(), false); - } else - added = addRow(grid, cellrow, getArg('[', ']')); - if (added) { - cellcol = 0; - if (grid.asHullInset()) - grid.asHullInset()->numbered( - cellrow, numbered); - cell = &grid.cell(grid.index(cellrow, - cellcol)); - } - } - -#if 0 - else if (t.cs() == "multicolumn") { - // extract column count and insert dummy cells - MathArray count; - parse(count, FLAG_ITEM, mode); - int cols = 1; - if (!extractNumber(count, cols)) { - lyxerr << " can't extract number of cells from " << count << endl; - } - // resize the table if necessary - for (int i = 0; i < cols; ++i) { - if (addCol(grid, cellcol)) { - cell = &grid.cell(grid.index( - cellrow, cellcol)); - // mark this as dummy - grid.cellinfo(grid.index( - cellrow, cellcol)).dummy_ = true; - } - } - // the last cell is the real thing, not a dummy - grid.cellinfo(grid.index(cellrow, cellcol)).dummy_ = false; - - // read special alignment - MathArray align; - parse(align, FLAG_ITEM, mode); - //grid.cellinfo(grid.index(cellrow, cellcol)).align_ = extractString(align); - - // parse the remaining contents into the "real" cell - parse(*cell, FLAG_ITEM, mode); - } -#endif - - else if (t.cs() == "limits") - limits = 1; - - else if (t.cs() == "nolimits") - limits = -1; - - else if (t.cs() == "nonumber") { - if (grid.asHullInset()) - grid.asHullInset()->numbered(cellrow, false); - } - - else if (t.cs() == "number") { - if (grid.asHullInset()) - grid.asHullInset()->numbered(cellrow, true); - } - - else if (t.cs() == "hline") { - grid.rowinfo(cellrow).lines_ ++; - } - - else if (t.cs() == "sqrt") { - MathArray ar; - parse(ar, FLAG_OPTION, mode); - if (ar.size()) { - cell->push_back(MathAtom(new InsetMathRoot)); - cell->back().nucleus()->cell(0) = ar; - parse(cell->back().nucleus()->cell(1), FLAG_ITEM, mode); - } else { - cell->push_back(MathAtom(new InsetMathSqrt)); - parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); - } - } - - else if (t.cs() == "xrightarrow" || t.cs() == "xleftarrow") { - cell->push_back(createInsetMath(t.cs())); - parse(cell->back().nucleus()->cell(1), FLAG_OPTION, mode); - parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); - } - - else if (t.cs() == "ref" || t.cs() == "prettyref" || - t.cs() == "pageref" || t.cs() == "vpageref" || t.cs() == "vref") { - cell->push_back(MathAtom(new RefInset(t.cs()))); - parse(cell->back().nucleus()->cell(1), FLAG_OPTION, mode); - parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); - } - - else if (t.cs() == "left") { - skipSpaces(); - Token const & tl = getToken(); - // \| and \Vert are equivalent, and InsetMathDelim - // can't handle \| - // FIXME: fix this in InsetMathDelim itself! - docstring const l = tl.cs() == "|" ? from_ascii("Vert") : tl.asString(); - MathArray ar; - parse(ar, FLAG_RIGHT, mode); - if (!good()) - break; - skipSpaces(); - Token const & tr = getToken(); - docstring const r = tr.cs() == "|" ? from_ascii("Vert") : tr.asString(); - cell->push_back(MathAtom(new InsetMathDelim(l, r, ar))); - } - - else if (t.cs() == "right") { - if (flags & FLAG_RIGHT) - return; - //lyxerr << "got so far: '" << cell << "'" << endl; - error("Unmatched right delimiter"); - return; - } - - else if (t.cs() == "begin") { - docstring const name = getArg('{', '}'); - environments_.push_back(name); - - if (name == "array" || name == "subarray") { - docstring const valign = parse_verbatim_option() + 'c'; - docstring const halign = parse_verbatim_item(); - cell->push_back(MathAtom(new InsetMathArray(name, (char)valign[0], halign))); - parse2(cell->back(), FLAG_END, mode, false); - } - - else if (name == "tabular") { - docstring const valign = parse_verbatim_option() + 'c'; - docstring const halign = parse_verbatim_item(); - cell->push_back(MathAtom(new InsetMathTabular(name, (char)valign[0], halign))); - parse2(cell->back(), FLAG_END, InsetMath::TEXT_MODE, false); - } - - else if (name == "split" || name == "cases") { - cell->push_back(createInsetMath(name)); - parse2(cell->back(), FLAG_END, mode, false); - } - - else if (name == "alignedat") { - docstring const valign = parse_verbatim_option() + 'c'; - // ignore this for a while - getArg('{', '}'); - cell->push_back(MathAtom(new InsetMathSplit(name, (char)valign[0]))); - parse2(cell->back(), FLAG_END, mode, false); - } - - else if (name == "math") { - cell->push_back(MathAtom(new InsetMathHull(hullSimple))); - parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, true); - } - - else if (name == "equation" || name == "equation*" - || name == "displaymath") { - cell->push_back(MathAtom(new InsetMathHull(hullEquation))); - parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, (name == "equation")); - } - - else if (name == "eqnarray" || name == "eqnarray*") { - cell->push_back(MathAtom(new InsetMathHull(hullEqnArray))); - parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); - } - - else if (name == "align" || name == "align*") { - cell->push_back(MathAtom(new InsetMathHull(hullAlign))); - parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); - } - - else if (name == "flalign" || name == "flalign*") { - cell->push_back(MathAtom(new InsetMathHull(hullFlAlign))); - parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); - } - - else if (name == "alignat" || name == "alignat*") { - // ignore this for a while - getArg('{', '}'); - cell->push_back(MathAtom(new InsetMathHull(hullAlignAt))); - parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); - } - - else if (name == "xalignat" || name == "xalignat*") { - // ignore this for a while - getArg('{', '}'); - cell->push_back(MathAtom(new InsetMathHull(hullXAlignAt))); - parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); - } - - else if (name == "xxalignat") { - // ignore this for a while - getArg('{', '}'); - cell->push_back(MathAtom(new InsetMathHull(hullXXAlignAt))); - parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); - } - - else if (name == "multline" || name == "multline*") { - cell->push_back(MathAtom(new InsetMathHull(hullMultline))); - parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); - } - - else if (name == "gather" || name == "gather*") { - cell->push_back(MathAtom(new InsetMathHull(hullGather))); - parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); - } - - else if (latexkeys const * l = in_word_set(name)) { - if (l->inset == "matrix") { - cell->push_back(createInsetMath(name)); - parse2(cell->back(), FLAG_END, mode, false); - } else if (l->inset == "split") { - docstring const valign = parse_verbatim_option() + 'c'; - cell->push_back(MathAtom(new InsetMathSplit(name, (char)valign[0]))); - parse2(cell->back(), FLAG_END, mode, false); - } else { - dump(); - lyxerr << "found math environment `" << to_utf8(name) - << "' in symbols file with unsupported inset `" - << to_utf8(l->inset) << "'." << endl; - // create generic environment inset - cell->push_back(MathAtom(new InsetMathEnv(name))); - parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); - } - } - - else { - dump(); - lyxerr << "found unknown math environment '" << to_utf8(name) - << "'" << endl; - // create generic environment inset - cell->push_back(MathAtom(new InsetMathEnv(name))); - parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); - } - } - - else if (t.cs() == "kern") { -#ifdef WITH_WARNINGS -#warning A hack... -#endif - docstring s; - while (true) { - Token const & t = getToken(); - if (!good()) { - putback(); - break; - } - s += t.character(); - if (isValidLength(to_utf8(s))) - break; - } - cell->push_back(MathAtom(new InsetMathKern(s))); - } - - else if (t.cs() == "label") { - // FIXME: This is swallowed in inline formulas - docstring label = parse_verbatim_item(); - MathArray ar; - asArray(label, ar); - if (grid.asHullInset()) { - grid.asHullInset()->label(cellrow, label); - } else { - cell->push_back(createInsetMath(t.cs())); - cell->push_back(MathAtom(new InsetMathBrace(ar))); - } - } - - else if (t.cs() == "choose" || t.cs() == "over" || t.cs() == "atop") { - MathAtom at = createInsetMath(t.cs()); - at.nucleus()->cell(0) = *cell; - cell->clear(); - parse(at.nucleus()->cell(1), flags, mode); - cell->push_back(at); - return; - } - - else if (t.cs() == "color") { - docstring const color = parse_verbatim_item(); - cell->push_back(MathAtom(new InsetMathColor(true, color))); - parse(cell->back().nucleus()->cell(0), flags, mode); - return; - } - - else if (t.cs() == "textcolor") { - docstring const color = parse_verbatim_item(); - cell->push_back(MathAtom(new InsetMathColor(false, color))); - parse(cell->back().nucleus()->cell(0), FLAG_ITEM, InsetMath::TEXT_MODE); - } - - else if (t.cs() == "normalcolor") { - cell->push_back(createInsetMath(t.cs())); - parse(cell->back().nucleus()->cell(0), flags, mode); - return; - } - - else if (t.cs() == "substack") { - cell->push_back(createInsetMath(t.cs())); - parse2(cell->back(), FLAG_ITEM, mode, false); - } - - else if (t.cs() == "xymatrix") { - odocstringstream os; - while (good() && nextToken().cat() != catBegin) - os << getToken().asInput(); - cell->push_back(createInsetMath(t.cs() + os.str())); - parse2(cell->back(), FLAG_ITEM, mode, false); - } - - else if (t.cs() == "framebox" || t.cs() == "makebox") { - cell->push_back(createInsetMath(t.cs())); - parse(cell->back().nucleus()->cell(0), FLAG_OPTION, InsetMath::TEXT_MODE); - parse(cell->back().nucleus()->cell(1), FLAG_OPTION, InsetMath::TEXT_MODE); - parse(cell->back().nucleus()->cell(2), FLAG_ITEM, InsetMath::TEXT_MODE); - } - - else if (t.cs() == "tag") { - if (nextToken().character() == '*') { - getToken(); - cell->push_back(createInsetMath(t.cs() + '*')); - } else - cell->push_back(createInsetMath(t.cs())); - parse(cell->back().nucleus()->cell(0), FLAG_ITEM, InsetMath::TEXT_MODE); - } - -#if 0 - else if (t.cs() == "infer") { - MathArray ar; - parse(ar, FLAG_OPTION, mode); - cell->push_back(createInsetMath(t.cs())); - parse2(cell->back(), FLAG_ITEM, mode, false); - } - - // Disabled - else if (1 && t.cs() == "ar") { - auto_ptr p(new InsetMathXYArrow); - // try to read target - parse(p->cell(0), FLAG_OTPTION, mode); - // try to read label - if (nextToken().cat() == catSuper || nextToken().cat() == catSub) { - p->up_ = nextToken().cat() == catSuper; - getToken(); - parse(p->cell(1), FLAG_ITEM, mode); - //lyxerr << "read label: " << p->cell(1) << endl; - } - - cell->push_back(MathAtom(p.release())); - //lyxerr << "read cell: " << cell << endl; - } -#endif - - else if (t.cs().size()) { - latexkeys const * l = in_word_set(t.cs()); - if (l) { - if (l->inset == "big") { - skipSpaces(); - docstring const delim = getToken().asInput(); - if (InsetMathBig::isBigInsetDelim(delim)) - cell->push_back(MathAtom( - new InsetMathBig(t.cs(), delim))); - else { - cell->push_back(createInsetMath(t.cs())); - putback(); - } - } - - else if (l->inset == "font") { - cell->push_back(createInsetMath(t.cs())); - parse(cell->back().nucleus()->cell(0), - FLAG_ITEM, asMode(mode, l->extra)); - } - - else if (l->inset == "oldfont") { - cell->push_back(createInsetMath(t.cs())); - parse(cell->back().nucleus()->cell(0), - flags | FLAG_ALIGN, asMode(mode, l->extra)); - if (prevToken().cat() != catAlign && - prevToken().cs() != "\\") - return; - putback(); - } - - else if (l->inset == "style") { - cell->push_back(createInsetMath(t.cs())); - parse(cell->back().nucleus()->cell(0), - flags | FLAG_ALIGN, mode); - if (prevToken().cat() != catAlign && - prevToken().cs() != "\\") - return; - putback(); - } - - else { - MathAtom at = createInsetMath(t.cs()); - for (InsetMath::idx_type i = 0; i < at->nargs(); ++i) - parse(at.nucleus()->cell(i), - FLAG_ITEM, asMode(mode, l->extra)); - cell->push_back(at); - } - } - - else { - MathAtom at = createInsetMath(t.cs()); - InsetMath::mode_type m = mode; - //if (m == InsetMath::UNDECIDED_MODE) - //lyxerr << "default creation: m1: " << m << endl; - if (at->currentMode() != InsetMath::UNDECIDED_MODE) - m = at->currentMode(); - //lyxerr << "default creation: m2: " << m << endl; - InsetMath::idx_type start = 0; - // this fails on \bigg[...\bigg] - //MathArray opt; - //parse(opt, FLAG_OPTION, InsetMath::VERBATIM_MODE); - //if (opt.size()) { - // start = 1; - // at.nucleus()->cell(0) = opt; - //} - for (InsetMath::idx_type i = start; i < at->nargs(); ++i) { - parse(at.nucleus()->cell(i), FLAG_ITEM, m); - skipSpaces(); - } - cell->push_back(at); - } - } - - - if (flags & FLAG_LEAVE) { - flags &= ~FLAG_LEAVE; - break; - } - } -} - - - -} // anonymous namespace - - -void mathed_parse_cell(MathArray & ar, docstring const & str) -{ - Parser(str).parse(ar, 0, InsetMath::MATH_MODE); -} - - -void mathed_parse_cell(MathArray & ar, istream & is) -{ - Parser(is).parse(ar, 0, InsetMath::MATH_MODE); -} - - -bool mathed_parse_normal(MathAtom & t, docstring const & str) -{ - return Parser(str).parse(t); -} - - -bool mathed_parse_normal(MathAtom & t, LyXLex & lex) -{ - return Parser(lex).parse(t); -} - - -void mathed_parse_normal(InsetMathGrid & grid, docstring const & str) -{ - Parser(str).parse1(grid, 0, InsetMath::MATH_MODE, false); -} - - -void initParser() -{ - fill(theCatcode, theCatcode + 128, catOther); - fill(theCatcode + 'a', theCatcode + 'z' + 1, catLetter); - fill(theCatcode + 'A', theCatcode + 'Z' + 1, catLetter); - - theCatcode[int('\\')] = catEscape; - theCatcode[int('{')] = catBegin; - theCatcode[int('}')] = catEnd; - theCatcode[int('$')] = catMath; - theCatcode[int('&')] = catAlign; - theCatcode[int('\n')] = catNewline; - theCatcode[int('#')] = catParameter; - theCatcode[int('^')] = catSuper; - theCatcode[int('_')] = catSub; - theCatcode[int(0x7f)] = catIgnore; - theCatcode[int(' ')] = catSpace; - theCatcode[int('\t')] = catSpace; - theCatcode[int('\r')] = catNewline; - theCatcode[int('~')] = catActive; - theCatcode[int('%')] = catComment; -} - - -} // namespace lyx diff --git a/src/mathed/MathParser.cpp b/src/mathed/MathParser.cpp new file mode 100644 index 0000000000..c985057b99 --- /dev/null +++ b/src/mathed/MathParser.cpp @@ -0,0 +1,1511 @@ +/** + * \file MathParser.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +/* + +If someone desperately needs partial "structures" (such as a few +cells of an array inset or similar) (s)he could uses the +following hack as starting point to write some macros: + + \newif\ifcomment + \commentfalse + \ifcomment + \def\makeamptab{\catcode`\&=4\relax} + \def\makeampletter{\catcode`\&=11\relax} + \def\b{\makeampletter\expandafter\makeamptab\bi} + \long\def\bi#1\e{} + \else + \def\b{}\def\e{} + \fi + + ... + + \[\begin{array}{ccc} +1 +& + + \end{array}\] + +*/ + + +#include + +#include "MathParser.h" + +#include "InsetMathArray.h" +#include "InsetMathBig.h" +#include "InsetMathBrace.h" +#include "InsetMathChar.h" +#include "InsetMathColor.h" +#include "InsetMathComment.h" +#include "InsetMathDelim.h" +#include "InsetMathEnv.h" +#include "InsetMathKern.h" +#include "InsetMathMacro.h" +#include "InsetMathPar.h" +#include "InsetMathRef.h" +#include "InsetMathRoot.h" +#include "InsetMathScript.h" +#include "InsetMathSplit.h" +#include "InsetMathSqrt.h" +#include "InsetMathTabular.h" +#include "MathMacroTemplate.h" +#include "MathFactory.h" +#include "MathMacroArgument.h" +#include "MathSupport.h" + +#include "lyxlex.h" +#include "debug.h" + +#include "support/convert.h" + +#include + + +namespace lyx { + +using std::endl; +using std::fill; + +using std::string; +using std::ios; +using std::istream; +using std::ostream; +using std::vector; + + +//#define FILEDEBUG + + +namespace { + +InsetMath::mode_type asMode(InsetMath::mode_type oldmode, docstring const & str) +{ + //lyxerr << "handling mode: '" << str << "'" << endl; + if (str == "mathmode") + return InsetMath::MATH_MODE; + if (str == "textmode" || str == "forcetext") + return InsetMath::TEXT_MODE; + return oldmode; +} + + +bool stared(docstring const & s) +{ + size_t const n = s.size(); + return n && s[n - 1] == '*'; +} + + +/*! + * Add the row \p cellrow to \p grid. + * \returns wether the row could be added. Adding a row can fail for + * environments like "equation" that have a fixed number of rows. + */ +bool addRow(InsetMathGrid & grid, InsetMathGrid::row_type & cellrow, + docstring const & vskip, bool allow_pagebreak = true) +{ + ++cellrow; + if (cellrow == grid.nrows()) { + //lyxerr << "adding row " << cellrow << endl; + grid.addRow(cellrow - 1); + if (cellrow == grid.nrows()) { + // We can't add a row to this grid, so let's + // append the content of this cell to the previous + // one. + // This does not happen in well formed .lyx files, + // but LyX versions 1.3.x and older could create + // such files and tex2lyx can still do that. + --cellrow; + lyxerr << "ignoring extra row"; + if (!vskip.empty()) + lyxerr << " with extra space " << to_utf8(vskip); + if (!allow_pagebreak) + lyxerr << " with no page break allowed"; + lyxerr << '.' << endl; + return false; + } + } + grid.vcrskip(LyXLength(to_utf8(vskip)), cellrow - 1); + grid.rowinfo(cellrow - 1).allow_pagebreak_ = allow_pagebreak; + return true; +} + + +/*! + * Add the column \p cellcol to \p grid. + * \returns wether the column could be added. Adding a column can fail for + * environments like "eqnarray" that have a fixed number of columns. + */ +bool addCol(InsetMathGrid & grid, InsetMathGrid::col_type & cellcol) +{ + ++cellcol; + if (cellcol == grid.ncols()) { + //lyxerr << "adding column " << cellcol << endl; + grid.addCol(cellcol - 1); + if (cellcol == grid.ncols()) { + // We can't add a column to this grid, so let's + // append the content of this cell to the previous + // one. + // This does not happen in well formed .lyx files, + // but LyX versions 1.3.x and older could create + // such files and tex2lyx can still do that. + --cellcol; + lyxerr << "ignoring extra column." << endl; + return false; + } + } + return true; +} + + +/*! + * Check wether the last row is empty and remove it if yes. + * Otherwise the following code + * \verbatim +\begin{array}{|c|c|} +\hline +1 & 2 \\ \hline +3 & 4 \\ \hline +\end{array} + * \endverbatim + * will result in a grid with 3 rows (+ the dummy row that is always present), + * because the last '\\' opens a new row. + */ +void delEmptyLastRow(InsetMathGrid & grid) +{ + InsetMathGrid::row_type const row = grid.nrows() - 1; + for (InsetMathGrid::col_type col = 0; col < grid.ncols(); ++col) { + if (!grid.cell(grid.index(row, col)).empty()) + return; + } + // Copy the row information of the empty row (which would contain the + // last hline in the example above) to the dummy row and delete the + // empty row. + grid.rowinfo(row + 1) = grid.rowinfo(row); + grid.delRow(row); +} + + +// These are TeX's catcodes +enum CatCode { + catEscape, // 0 backslash + catBegin, // 1 { + catEnd, // 2 } + catMath, // 3 $ + catAlign, // 4 & + catNewline, // 5 ^^M + catParameter, // 6 # + catSuper, // 7 ^ + catSub, // 8 _ + catIgnore, // 9 + catSpace, // 10 space + catLetter, // 11 a-zA-Z + catOther, // 12 none of the above + catActive, // 13 ~ + catComment, // 14 % + catInvalid // 15 +}; + +CatCode theCatcode[128]; + + +inline CatCode catcode(char_type c) +{ + /* The only characters that are not catOther lie in the pure ASCII + * range. Therefore theCatcode has only 128 entries. + * TeX itself deals with 8bit characters, so if needed this table + * could be enlarged to 256 entries. + * Any larger value does not make sense, since the fact that we use + * unicode internally does not change Knuth's TeX engine. + * Apart from that a table for the full 21bit UCS4 range would waste + * too much memory. */ + if (c >= 128) + return catOther; + + return theCatcode[c]; +} + + +enum { + FLAG_ALIGN = 1 << 0, // next & or \\ ends the parsing process + FLAG_BRACE_LAST = 1 << 1, // next closing brace ends the parsing + FLAG_RIGHT = 1 << 2, // next \\right ends the parsing process + FLAG_END = 1 << 3, // next \\end ends the parsing process + FLAG_BRACK_LAST = 1 << 4, // next closing bracket ends the parsing + FLAG_TEXTMODE = 1 << 5, // we are in a box + FLAG_ITEM = 1 << 6, // read a (possibly braced token) + FLAG_LEAVE = 1 << 7, // leave the loop at the end + FLAG_SIMPLE = 1 << 8, // next $ leaves the loop + FLAG_EQUATION = 1 << 9, // next \] leaves the loop + FLAG_SIMPLE2 = 1 << 10, // next \) leaves the loop + FLAG_OPTION = 1 << 11, // read [...] style option + FLAG_BRACED = 1 << 12 // read {...} style argument +}; + + +// +// Helper class for parsing +// + +class Token { +public: + /// + Token() : cs_(), char_(0), cat_(catIgnore) {} + /// + Token(char_type c, CatCode cat) : cs_(), char_(c), cat_(cat) {} + /// + explicit Token(docstring const & cs) : cs_(cs), char_(0), cat_(catIgnore) {} + + /// + docstring const & cs() const { return cs_; } + /// + CatCode cat() const { return cat_; } + /// + char_type character() const { return char_; } + /// + docstring asString() const { return cs_.size() ? cs_ : docstring(1, char_); } + /// + docstring asInput() const { return cs_.size() ? '\\' + cs_ : docstring(1, char_); } + +private: + /// + docstring cs_; + /// + char_type char_; + /// + CatCode cat_; +}; + + +ostream & operator<<(ostream & os, Token const & t) +{ + if (t.cs().size()) { + docstring const & cs = t.cs(); + // FIXME: For some strange reason, the stream operator instanciate + // a new Token before outputting the contents of t.cs(). + // Because of this the line + // os << '\\' << cs; + // below becomes recursive. + // In order to avoid that we return early: + if (cs == "\\") + return os; + os << '\\' << to_utf8(cs); + } + else if (t.cat() == catLetter) + os << t.character(); + else + os << '[' << t.character() << ',' << t.cat() << ']'; + return os; +} + + +class Parser { +public: + /// + typedef InsetMath::mode_type mode_type; + + /// + Parser(LyXLex & lex); + /// Only use this for reading from .lyx file format, for the reason + /// see Parser::tokenize(std::istream &). + Parser(istream & is); + /// + Parser(docstring const & str); + + /// + bool parse(MathAtom & at); + /// + void parse(MathArray & array, unsigned flags, mode_type mode); + /// + void parse1(InsetMathGrid & grid, unsigned flags, mode_type mode, + bool numbered); + /// + MathArray parse(unsigned flags, mode_type mode); + /// + int lineno() const { return lineno_; } + /// + void putback(); + +private: + /// + void parse2(MathAtom & at, unsigned flags, mode_type mode, bool numbered); + /// get arg delimited by 'left' and 'right' + docstring getArg(char_type left, char_type right); + /// + char_type getChar(); + /// + void error(string const & msg); + void error(docstring const & msg) { error(to_utf8(msg)); } + /// dump contents to screen + void dump() const; + /// Only use this for reading from .lyx file format (see + /// implementation for reason) + void tokenize(istream & is); + /// + void tokenize(docstring const & s); + /// + void skipSpaceTokens(idocstream & is, char_type c); + /// + void push_back(Token const & t); + /// + void pop_back(); + /// + Token const & prevToken() const; + /// + Token const & nextToken() const; + /// + Token const & getToken(); + /// skips spaces if any + void skipSpaces(); + /// + void lex(docstring const & s); + /// + bool good() const; + /// + docstring parse_verbatim_item(); + /// + docstring parse_verbatim_option(); + + /// + int lineno_; + /// + vector tokens_; + /// + unsigned pos_; + /// Stack of active environments + vector environments_; +}; + + +Parser::Parser(LyXLex & lexer) + : lineno_(lexer.getLineNo()), pos_(0) +{ + tokenize(lexer.getStream()); + lexer.eatLine(); +} + + +Parser::Parser(istream & is) + : lineno_(0), pos_(0) +{ + tokenize(is); +} + + +Parser::Parser(docstring const & str) + : lineno_(0), pos_(0) +{ + tokenize(str); +} + + +void Parser::push_back(Token const & t) +{ + tokens_.push_back(t); +} + + +void Parser::pop_back() +{ + tokens_.pop_back(); +} + + +Token const & Parser::prevToken() const +{ + static const Token dummy; + return pos_ > 0 ? tokens_[pos_ - 1] : dummy; +} + + +Token const & Parser::nextToken() const +{ + static const Token dummy; + return good() ? tokens_[pos_] : dummy; +} + + +Token const & Parser::getToken() +{ + static const Token dummy; + //lyxerr << "looking at token " << tokens_[pos_] << " pos: " << pos_ << endl; + return good() ? tokens_[pos_++] : dummy; +} + + +void Parser::skipSpaces() +{ + while (nextToken().cat() == catSpace || nextToken().cat() == catNewline) + getToken(); +} + + +void Parser::putback() +{ + --pos_; +} + + +bool Parser::good() const +{ + return pos_ < tokens_.size(); +} + + +char_type Parser::getChar() +{ + if (!good()) + error("The input stream is not well..."); + return tokens_[pos_++].character(); +} + + +docstring Parser::getArg(char_type left, char_type right) +{ + skipSpaces(); + + docstring result; + char_type c = getChar(); + + if (c != left) + putback(); + else + while ((c = getChar()) != right && good()) + result += c; + + return result; +} + + +void Parser::skipSpaceTokens(idocstream & is, char_type c) +{ + // skip trailing spaces + while (catcode(c) == catSpace || catcode(c) == catNewline) + if (!is.get(c)) + break; + //lyxerr << "putting back: " << c << endl; + is.putback(c); +} + + +void Parser::tokenize(istream & is) +{ + // eat everything up to the next \end_inset or end of stream + // and store it in s for further tokenization + string s; + char c; + while (is.get(c)) { + s += c; + if (s.size() >= 10 && s.substr(s.size() - 10) == "\\end_inset") { + s = s.substr(0, s.size() - 10); + break; + } + } + // Remove the space after \end_inset + if (is.get(c) && c != ' ') + is.unget(); + + // tokenize buffer + tokenize(from_utf8(s)); +} + + +void Parser::tokenize(docstring const & buffer) +{ + idocstringstream is(buffer, ios::in | ios::binary); + + char_type c; + while (is.get(c)) { + //lyxerr << "reading c: " << c << endl; + + switch (catcode(c)) { + case catNewline: { + ++lineno_; + is.get(c); + if (catcode(c) == catNewline) + ; //push_back(Token("par")); + else { + push_back(Token('\n', catNewline)); + is.putback(c); + } + break; + } + +/* + case catComment: { + while (is.get(c) && catcode(c) != catNewline) + ; + ++lineno_; + break; + } +*/ + + case catEscape: { + is.get(c); + if (!is) { + error("unexpected end of input"); + } else { + docstring s(1, c); + if (catcode(c) == catLetter) { + // collect letters + while (is.get(c) && catcode(c) == catLetter) + s += c; + skipSpaceTokens(is, c); + } + push_back(Token(s)); + } + break; + } + + case catSuper: + case catSub: { + push_back(Token(c, catcode(c))); + is.get(c); + skipSpaceTokens(is, c); + break; + } + + case catIgnore: { + lyxerr << "ignoring a char: " << int(c) << endl; + break; + } + + default: + push_back(Token(c, catcode(c))); + } + } + +#ifdef FILEDEBUG + dump(); +#endif +} + + +void Parser::dump() const +{ + lyxerr << "\nTokens: "; + for (unsigned i = 0; i < tokens_.size(); ++i) { + if (i == pos_) + lyxerr << " <#> "; + lyxerr << tokens_[i]; + } + lyxerr << " pos: " << pos_ << endl; +} + + +void Parser::error(string const & msg) +{ + lyxerr << "Line ~" << lineno_ << ": Math parse error: " << msg << endl; + dump(); + //exit(1); +} + + +bool Parser::parse(MathAtom & at) +{ + skipSpaces(); + MathArray ar; + parse(ar, false, InsetMath::UNDECIDED_MODE); + if (ar.size() != 1 || ar.front()->getType() == hullNone) { + lyxerr << "unusual contents found: " << ar << endl; + at = MathAtom(new InsetMathPar(ar)); + //if (at->nargs() > 0) + // at.nucleus()->cell(0) = ar; + //else + // lyxerr << "unusual contents found: " << ar << endl; + return true; + } + at = ar[0]; + return true; +} + + +docstring Parser::parse_verbatim_option() +{ + skipSpaces(); + docstring res; + if (nextToken().character() == '[') { + Token t = getToken(); + for (Token t = getToken(); t.character() != ']' && good(); t = getToken()) { + if (t.cat() == catBegin) { + putback(); + res += '{' + parse_verbatim_item() + '}'; + } else + res += t.asString(); + } + } + return res; +} + + +docstring Parser::parse_verbatim_item() +{ + skipSpaces(); + docstring res; + if (nextToken().cat() == catBegin) { + Token t = getToken(); + for (Token t = getToken(); t.cat() != catEnd && good(); t = getToken()) { + if (t.cat() == catBegin) { + putback(); + res += '{' + parse_verbatim_item() + '}'; + } + else + res += t.asString(); + } + } + return res; +} + + +MathArray Parser::parse(unsigned flags, mode_type mode) +{ + MathArray ar; + parse(ar, flags, mode); + return ar; +} + + +void Parser::parse(MathArray & array, unsigned flags, mode_type mode) +{ + InsetMathGrid grid(1, 1); + parse1(grid, flags, mode, false); + array = grid.cell(0); +} + + +void Parser::parse2(MathAtom & at, const unsigned flags, const mode_type mode, + const bool numbered) +{ + parse1(*(at.nucleus()->asGridInset()), flags, mode, numbered); +} + + +void Parser::parse1(InsetMathGrid & grid, unsigned flags, + const mode_type mode, const bool numbered) +{ + int limits = 0; + InsetMathGrid::row_type cellrow = 0; + InsetMathGrid::col_type cellcol = 0; + MathArray * cell = &grid.cell(grid.index(cellrow, cellcol)); + + if (grid.asHullInset()) + grid.asHullInset()->numbered(cellrow, numbered); + + //dump(); + //lyxerr << " flags: " << flags << endl; + //lyxerr << " mode: " << mode << endl; + //lyxerr << "grid: " << grid << endl; + + while (good()) { + Token const & t = getToken(); + +#ifdef FILEDEBUG + lyxerr << "t: " << t << " flags: " << flags << endl; + lyxerr << "mode: " << mode << endl; + cell->dump(); + lyxerr << endl; +#endif + + if (flags & FLAG_ITEM) { + + if (t.cat() == catBegin) { + // skip the brace and collect everything to the next matching + // closing brace + parse1(grid, FLAG_BRACE_LAST, mode, numbered); + return; + } + + // handle only this single token, leave the loop if done + flags = FLAG_LEAVE; + } + + + if (flags & FLAG_BRACED) { + if (t.cat() == catSpace) + continue; + + if (t.cat() != catBegin) { + error("opening brace expected"); + return; + } + + // skip the brace and collect everything to the next matching + // closing brace + flags = FLAG_BRACE_LAST; + } + + + if (flags & FLAG_OPTION) { + if (t.cat() == catOther && t.character() == '[') { + MathArray ar; + parse(ar, FLAG_BRACK_LAST, mode); + cell->append(ar); + } else { + // no option found, put back token and we are done + putback(); + } + return; + } + + // + // cat codes + // + if (t.cat() == catMath) { + if (mode != InsetMath::MATH_MODE) { + // we are inside some text mode thingy, so opening new math is allowed + Token const & n = getToken(); + if (n.cat() == catMath) { + // TeX's $$...$$ syntax for displayed math + cell->push_back(MathAtom(new InsetMathHull(hullEquation))); + parse2(cell->back(), FLAG_SIMPLE, InsetMath::MATH_MODE, false); + getToken(); // skip the second '$' token + } else { + // simple $...$ stuff + putback(); + cell->push_back(MathAtom(new InsetMathHull(hullSimple))); + parse2(cell->back(), FLAG_SIMPLE, InsetMath::MATH_MODE, false); + } + } + + else if (flags & FLAG_SIMPLE) { + // this is the end of the formula + return; + } + + else { + error("something strange in the parser"); + break; + } + } + + else if (t.cat() == catLetter) + cell->push_back(MathAtom(new InsetMathChar(t.character()))); + + else if (t.cat() == catSpace && mode != InsetMath::MATH_MODE) { + if (cell->empty() || cell->back()->getChar() != ' ') + cell->push_back(MathAtom(new InsetMathChar(t.character()))); + } + + else if (t.cat() == catNewline && mode != InsetMath::MATH_MODE) { + if (cell->empty() || cell->back()->getChar() != ' ') + cell->push_back(MathAtom(new InsetMathChar(' '))); + } + + else if (t.cat() == catParameter) { + Token const & n = getToken(); + cell->push_back(MathAtom(new MathMacroArgument(n.character()-'0'))); + } + + else if (t.cat() == catActive) + cell->push_back(MathAtom(new InsetMathChar(t.character()))); + + else if (t.cat() == catBegin) { + MathArray ar; + parse(ar, FLAG_BRACE_LAST, mode); + // do not create a BraceInset if they were written by LyX + // this helps to keep the annoyance of "a choose b" to a minimum + if (ar.size() == 1 && ar[0]->extraBraces()) + cell->append(ar); + else + cell->push_back(MathAtom(new InsetMathBrace(ar))); + } + + else if (t.cat() == catEnd) { + if (flags & FLAG_BRACE_LAST) + return; + error("found '}' unexpectedly"); + //BOOST_ASSERT(false); + //add(cell, '}', LM_TC_TEX); + } + + else if (t.cat() == catAlign) { + //lyxerr << " column now " << (cellcol + 1) + // << " max: " << grid.ncols() << endl; + if (flags & FLAG_ALIGN) + return; + if (addCol(grid, cellcol)) + cell = &grid.cell(grid.index(cellrow, cellcol)); + } + + else if (t.cat() == catSuper || t.cat() == catSub) { + bool up = (t.cat() == catSuper); + // we need no new script inset if the last thing was a scriptinset, + // which has that script already not the same script already + if (!cell->size()) + cell->push_back(MathAtom(new InsetMathScript(up))); + else if (cell->back()->asScriptInset() && + !cell->back()->asScriptInset()->has(up)) + cell->back().nucleus()->asScriptInset()->ensure(up); + else if (cell->back()->asScriptInset()) + cell->push_back(MathAtom(new InsetMathScript(up))); + else + cell->back() = MathAtom(new InsetMathScript(cell->back(), up)); + InsetMathScript * p = cell->back().nucleus()->asScriptInset(); + // special handling of {}-bases + // Here we could remove the brace inset for things + // like {a'}^2 and add the braces back in + // InsetMathScript::write(). + // We do not do it, since it is not possible to detect + // reliably whether the braces are needed because the + // nucleus contains more than one symbol, or whether + // they are needed for unknown commands like \xx{a}_0 + // or \yy{a}{b}_0. This was done in revision 14819 + // in an unreliable way. See this thread + // http://www.mail-archive.com/lyx-devel%40lists.lyx.org/msg104917.html + // for more details. + parse(p->cell(p->idxOfScript(up)), FLAG_ITEM, mode); + if (limits) { + p->limits(limits); + limits = 0; + } + } + + else if (t.character() == ']' && (flags & FLAG_BRACK_LAST)) { + //lyxerr << "finished reading option" << endl; + return; + } + + else if (t.cat() == catOther) + cell->push_back(MathAtom(new InsetMathChar(t.character()))); + + else if (t.cat() == catComment) { + docstring s; + while (good()) { + Token const & t = getToken(); + if (t.cat() == catNewline) + break; + s += t.asString(); + } + cell->push_back(MathAtom(new InsetMathComment(s))); + skipSpaces(); + } + + // + // control sequences + // + + else if (t.cs() == "lyxlock") { + if (cell->size()) + cell->back().nucleus()->lock(true); + } + + else if (t.cs() == "def" || + t.cs() == "newcommand" || + t.cs() == "renewcommand") + { + docstring const type = t.cs(); + docstring name; + int nargs = 0; + if (t.cs() == "def") { + // get name + name = getToken().cs(); + + // read parameter + docstring pars; + while (good() && nextToken().cat() != catBegin) { + pars += getToken().cs(); + ++nargs; + } + nargs /= 2; + //lyxerr << "read \\def parameter list '" << pars << "'" << endl; + + } else { // t.cs() == "newcommand" || t.cs() == "renewcommand" + + if (getToken().cat() != catBegin) { + error("'{' in \\newcommand expected (1) "); + return; + } + + name = getToken().cs(); + + if (getToken().cat() != catEnd) { + error("'}' in \\newcommand expected"); + return; + } + + docstring const arg = getArg('[', ']'); + if (!arg.empty()) + nargs = convert(arg); + + } + + MathArray ar1; + parse(ar1, FLAG_ITEM, InsetMath::UNDECIDED_MODE); + + // we cannot handle recursive stuff at all + //MathArray test; + //test.push_back(createInsetMath(name)); + //if (ar1.contains(test)) { + // error("we cannot handle recursive macros at all."); + // return; + //} + + // is a version for display attached? + skipSpaces(); + MathArray ar2; + if (nextToken().cat() == catBegin) + parse(ar2, FLAG_ITEM, InsetMath::MATH_MODE); + + cell->push_back(MathAtom(new MathMacroTemplate(name, nargs, type, + ar1, ar2))); + } + + else if (t.cs() == "(") { + cell->push_back(MathAtom(new InsetMathHull(hullSimple))); + parse2(cell->back(), FLAG_SIMPLE2, InsetMath::MATH_MODE, false); + } + + else if (t.cs() == "[") { + cell->push_back(MathAtom(new InsetMathHull(hullEquation))); + parse2(cell->back(), FLAG_EQUATION, InsetMath::MATH_MODE, false); + } + + else if (t.cs() == "protect") + // ignore \\protect, will hopefully be re-added during output + ; + + else if (t.cs() == "end") { + if (flags & FLAG_END) { + // eat environment name + docstring const name = getArg('{', '}'); + if (environments_.empty()) + error("'found \\end{" + name + + "}' without matching '\\begin{" + + name + "}'"); + else if (name != environments_.back()) + error("'\\end{" + name + + "}' does not match '\\begin{" + + environments_.back() + "}'"); + else { + environments_.pop_back(); + // Delete empty last row in matrix + // like insets. + // If you abuse InsetMathGrid for + // non-matrix like structures you + // probably need to refine this test. + // Right now we only have to test for + // single line hull insets. + if (grid.nrows() > 1) + delEmptyLastRow(grid); + return; + } + } else + error("found 'end' unexpectedly"); + } + + else if (t.cs() == ")") { + if (flags & FLAG_SIMPLE2) + return; + error("found '\\)' unexpectedly"); + } + + else if (t.cs() == "]") { + if (flags & FLAG_EQUATION) + return; + error("found '\\]' unexpectedly"); + } + + else if (t.cs() == "\\") { + if (flags & FLAG_ALIGN) + return; + bool added; + if (nextToken().asInput() == "*") { + getToken(); + added = addRow(grid, cellrow, docstring(), false); + } else + added = addRow(grid, cellrow, getArg('[', ']')); + if (added) { + cellcol = 0; + if (grid.asHullInset()) + grid.asHullInset()->numbered( + cellrow, numbered); + cell = &grid.cell(grid.index(cellrow, + cellcol)); + } + } + +#if 0 + else if (t.cs() == "multicolumn") { + // extract column count and insert dummy cells + MathArray count; + parse(count, FLAG_ITEM, mode); + int cols = 1; + if (!extractNumber(count, cols)) { + lyxerr << " can't extract number of cells from " << count << endl; + } + // resize the table if necessary + for (int i = 0; i < cols; ++i) { + if (addCol(grid, cellcol)) { + cell = &grid.cell(grid.index( + cellrow, cellcol)); + // mark this as dummy + grid.cellinfo(grid.index( + cellrow, cellcol)).dummy_ = true; + } + } + // the last cell is the real thing, not a dummy + grid.cellinfo(grid.index(cellrow, cellcol)).dummy_ = false; + + // read special alignment + MathArray align; + parse(align, FLAG_ITEM, mode); + //grid.cellinfo(grid.index(cellrow, cellcol)).align_ = extractString(align); + + // parse the remaining contents into the "real" cell + parse(*cell, FLAG_ITEM, mode); + } +#endif + + else if (t.cs() == "limits") + limits = 1; + + else if (t.cs() == "nolimits") + limits = -1; + + else if (t.cs() == "nonumber") { + if (grid.asHullInset()) + grid.asHullInset()->numbered(cellrow, false); + } + + else if (t.cs() == "number") { + if (grid.asHullInset()) + grid.asHullInset()->numbered(cellrow, true); + } + + else if (t.cs() == "hline") { + grid.rowinfo(cellrow).lines_ ++; + } + + else if (t.cs() == "sqrt") { + MathArray ar; + parse(ar, FLAG_OPTION, mode); + if (ar.size()) { + cell->push_back(MathAtom(new InsetMathRoot)); + cell->back().nucleus()->cell(0) = ar; + parse(cell->back().nucleus()->cell(1), FLAG_ITEM, mode); + } else { + cell->push_back(MathAtom(new InsetMathSqrt)); + parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); + } + } + + else if (t.cs() == "xrightarrow" || t.cs() == "xleftarrow") { + cell->push_back(createInsetMath(t.cs())); + parse(cell->back().nucleus()->cell(1), FLAG_OPTION, mode); + parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); + } + + else if (t.cs() == "ref" || t.cs() == "prettyref" || + t.cs() == "pageref" || t.cs() == "vpageref" || t.cs() == "vref") { + cell->push_back(MathAtom(new RefInset(t.cs()))); + parse(cell->back().nucleus()->cell(1), FLAG_OPTION, mode); + parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); + } + + else if (t.cs() == "left") { + skipSpaces(); + Token const & tl = getToken(); + // \| and \Vert are equivalent, and InsetMathDelim + // can't handle \| + // FIXME: fix this in InsetMathDelim itself! + docstring const l = tl.cs() == "|" ? from_ascii("Vert") : tl.asString(); + MathArray ar; + parse(ar, FLAG_RIGHT, mode); + if (!good()) + break; + skipSpaces(); + Token const & tr = getToken(); + docstring const r = tr.cs() == "|" ? from_ascii("Vert") : tr.asString(); + cell->push_back(MathAtom(new InsetMathDelim(l, r, ar))); + } + + else if (t.cs() == "right") { + if (flags & FLAG_RIGHT) + return; + //lyxerr << "got so far: '" << cell << "'" << endl; + error("Unmatched right delimiter"); + return; + } + + else if (t.cs() == "begin") { + docstring const name = getArg('{', '}'); + environments_.push_back(name); + + if (name == "array" || name == "subarray") { + docstring const valign = parse_verbatim_option() + 'c'; + docstring const halign = parse_verbatim_item(); + cell->push_back(MathAtom(new InsetMathArray(name, (char)valign[0], halign))); + parse2(cell->back(), FLAG_END, mode, false); + } + + else if (name == "tabular") { + docstring const valign = parse_verbatim_option() + 'c'; + docstring const halign = parse_verbatim_item(); + cell->push_back(MathAtom(new InsetMathTabular(name, (char)valign[0], halign))); + parse2(cell->back(), FLAG_END, InsetMath::TEXT_MODE, false); + } + + else if (name == "split" || name == "cases") { + cell->push_back(createInsetMath(name)); + parse2(cell->back(), FLAG_END, mode, false); + } + + else if (name == "alignedat") { + docstring const valign = parse_verbatim_option() + 'c'; + // ignore this for a while + getArg('{', '}'); + cell->push_back(MathAtom(new InsetMathSplit(name, (char)valign[0]))); + parse2(cell->back(), FLAG_END, mode, false); + } + + else if (name == "math") { + cell->push_back(MathAtom(new InsetMathHull(hullSimple))); + parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, true); + } + + else if (name == "equation" || name == "equation*" + || name == "displaymath") { + cell->push_back(MathAtom(new InsetMathHull(hullEquation))); + parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, (name == "equation")); + } + + else if (name == "eqnarray" || name == "eqnarray*") { + cell->push_back(MathAtom(new InsetMathHull(hullEqnArray))); + parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); + } + + else if (name == "align" || name == "align*") { + cell->push_back(MathAtom(new InsetMathHull(hullAlign))); + parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); + } + + else if (name == "flalign" || name == "flalign*") { + cell->push_back(MathAtom(new InsetMathHull(hullFlAlign))); + parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); + } + + else if (name == "alignat" || name == "alignat*") { + // ignore this for a while + getArg('{', '}'); + cell->push_back(MathAtom(new InsetMathHull(hullAlignAt))); + parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); + } + + else if (name == "xalignat" || name == "xalignat*") { + // ignore this for a while + getArg('{', '}'); + cell->push_back(MathAtom(new InsetMathHull(hullXAlignAt))); + parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); + } + + else if (name == "xxalignat") { + // ignore this for a while + getArg('{', '}'); + cell->push_back(MathAtom(new InsetMathHull(hullXXAlignAt))); + parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); + } + + else if (name == "multline" || name == "multline*") { + cell->push_back(MathAtom(new InsetMathHull(hullMultline))); + parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); + } + + else if (name == "gather" || name == "gather*") { + cell->push_back(MathAtom(new InsetMathHull(hullGather))); + parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); + } + + else if (latexkeys const * l = in_word_set(name)) { + if (l->inset == "matrix") { + cell->push_back(createInsetMath(name)); + parse2(cell->back(), FLAG_END, mode, false); + } else if (l->inset == "split") { + docstring const valign = parse_verbatim_option() + 'c'; + cell->push_back(MathAtom(new InsetMathSplit(name, (char)valign[0]))); + parse2(cell->back(), FLAG_END, mode, false); + } else { + dump(); + lyxerr << "found math environment `" << to_utf8(name) + << "' in symbols file with unsupported inset `" + << to_utf8(l->inset) << "'." << endl; + // create generic environment inset + cell->push_back(MathAtom(new InsetMathEnv(name))); + parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); + } + } + + else { + dump(); + lyxerr << "found unknown math environment '" << to_utf8(name) + << "'" << endl; + // create generic environment inset + cell->push_back(MathAtom(new InsetMathEnv(name))); + parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); + } + } + + else if (t.cs() == "kern") { +#ifdef WITH_WARNINGS +#warning A hack... +#endif + docstring s; + while (true) { + Token const & t = getToken(); + if (!good()) { + putback(); + break; + } + s += t.character(); + if (isValidLength(to_utf8(s))) + break; + } + cell->push_back(MathAtom(new InsetMathKern(s))); + } + + else if (t.cs() == "label") { + // FIXME: This is swallowed in inline formulas + docstring label = parse_verbatim_item(); + MathArray ar; + asArray(label, ar); + if (grid.asHullInset()) { + grid.asHullInset()->label(cellrow, label); + } else { + cell->push_back(createInsetMath(t.cs())); + cell->push_back(MathAtom(new InsetMathBrace(ar))); + } + } + + else if (t.cs() == "choose" || t.cs() == "over" || t.cs() == "atop") { + MathAtom at = createInsetMath(t.cs()); + at.nucleus()->cell(0) = *cell; + cell->clear(); + parse(at.nucleus()->cell(1), flags, mode); + cell->push_back(at); + return; + } + + else if (t.cs() == "color") { + docstring const color = parse_verbatim_item(); + cell->push_back(MathAtom(new InsetMathColor(true, color))); + parse(cell->back().nucleus()->cell(0), flags, mode); + return; + } + + else if (t.cs() == "textcolor") { + docstring const color = parse_verbatim_item(); + cell->push_back(MathAtom(new InsetMathColor(false, color))); + parse(cell->back().nucleus()->cell(0), FLAG_ITEM, InsetMath::TEXT_MODE); + } + + else if (t.cs() == "normalcolor") { + cell->push_back(createInsetMath(t.cs())); + parse(cell->back().nucleus()->cell(0), flags, mode); + return; + } + + else if (t.cs() == "substack") { + cell->push_back(createInsetMath(t.cs())); + parse2(cell->back(), FLAG_ITEM, mode, false); + } + + else if (t.cs() == "xymatrix") { + odocstringstream os; + while (good() && nextToken().cat() != catBegin) + os << getToken().asInput(); + cell->push_back(createInsetMath(t.cs() + os.str())); + parse2(cell->back(), FLAG_ITEM, mode, false); + } + + else if (t.cs() == "framebox" || t.cs() == "makebox") { + cell->push_back(createInsetMath(t.cs())); + parse(cell->back().nucleus()->cell(0), FLAG_OPTION, InsetMath::TEXT_MODE); + parse(cell->back().nucleus()->cell(1), FLAG_OPTION, InsetMath::TEXT_MODE); + parse(cell->back().nucleus()->cell(2), FLAG_ITEM, InsetMath::TEXT_MODE); + } + + else if (t.cs() == "tag") { + if (nextToken().character() == '*') { + getToken(); + cell->push_back(createInsetMath(t.cs() + '*')); + } else + cell->push_back(createInsetMath(t.cs())); + parse(cell->back().nucleus()->cell(0), FLAG_ITEM, InsetMath::TEXT_MODE); + } + +#if 0 + else if (t.cs() == "infer") { + MathArray ar; + parse(ar, FLAG_OPTION, mode); + cell->push_back(createInsetMath(t.cs())); + parse2(cell->back(), FLAG_ITEM, mode, false); + } + + // Disabled + else if (1 && t.cs() == "ar") { + auto_ptr p(new InsetMathXYArrow); + // try to read target + parse(p->cell(0), FLAG_OTPTION, mode); + // try to read label + if (nextToken().cat() == catSuper || nextToken().cat() == catSub) { + p->up_ = nextToken().cat() == catSuper; + getToken(); + parse(p->cell(1), FLAG_ITEM, mode); + //lyxerr << "read label: " << p->cell(1) << endl; + } + + cell->push_back(MathAtom(p.release())); + //lyxerr << "read cell: " << cell << endl; + } +#endif + + else if (t.cs().size()) { + latexkeys const * l = in_word_set(t.cs()); + if (l) { + if (l->inset == "big") { + skipSpaces(); + docstring const delim = getToken().asInput(); + if (InsetMathBig::isBigInsetDelim(delim)) + cell->push_back(MathAtom( + new InsetMathBig(t.cs(), delim))); + else { + cell->push_back(createInsetMath(t.cs())); + putback(); + } + } + + else if (l->inset == "font") { + cell->push_back(createInsetMath(t.cs())); + parse(cell->back().nucleus()->cell(0), + FLAG_ITEM, asMode(mode, l->extra)); + } + + else if (l->inset == "oldfont") { + cell->push_back(createInsetMath(t.cs())); + parse(cell->back().nucleus()->cell(0), + flags | FLAG_ALIGN, asMode(mode, l->extra)); + if (prevToken().cat() != catAlign && + prevToken().cs() != "\\") + return; + putback(); + } + + else if (l->inset == "style") { + cell->push_back(createInsetMath(t.cs())); + parse(cell->back().nucleus()->cell(0), + flags | FLAG_ALIGN, mode); + if (prevToken().cat() != catAlign && + prevToken().cs() != "\\") + return; + putback(); + } + + else { + MathAtom at = createInsetMath(t.cs()); + for (InsetMath::idx_type i = 0; i < at->nargs(); ++i) + parse(at.nucleus()->cell(i), + FLAG_ITEM, asMode(mode, l->extra)); + cell->push_back(at); + } + } + + else { + MathAtom at = createInsetMath(t.cs()); + InsetMath::mode_type m = mode; + //if (m == InsetMath::UNDECIDED_MODE) + //lyxerr << "default creation: m1: " << m << endl; + if (at->currentMode() != InsetMath::UNDECIDED_MODE) + m = at->currentMode(); + //lyxerr << "default creation: m2: " << m << endl; + InsetMath::idx_type start = 0; + // this fails on \bigg[...\bigg] + //MathArray opt; + //parse(opt, FLAG_OPTION, InsetMath::VERBATIM_MODE); + //if (opt.size()) { + // start = 1; + // at.nucleus()->cell(0) = opt; + //} + for (InsetMath::idx_type i = start; i < at->nargs(); ++i) { + parse(at.nucleus()->cell(i), FLAG_ITEM, m); + skipSpaces(); + } + cell->push_back(at); + } + } + + + if (flags & FLAG_LEAVE) { + flags &= ~FLAG_LEAVE; + break; + } + } +} + + + +} // anonymous namespace + + +void mathed_parse_cell(MathArray & ar, docstring const & str) +{ + Parser(str).parse(ar, 0, InsetMath::MATH_MODE); +} + + +void mathed_parse_cell(MathArray & ar, istream & is) +{ + Parser(is).parse(ar, 0, InsetMath::MATH_MODE); +} + + +bool mathed_parse_normal(MathAtom & t, docstring const & str) +{ + return Parser(str).parse(t); +} + + +bool mathed_parse_normal(MathAtom & t, LyXLex & lex) +{ + return Parser(lex).parse(t); +} + + +void mathed_parse_normal(InsetMathGrid & grid, docstring const & str) +{ + Parser(str).parse1(grid, 0, InsetMath::MATH_MODE, false); +} + + +void initParser() +{ + fill(theCatcode, theCatcode + 128, catOther); + fill(theCatcode + 'a', theCatcode + 'z' + 1, catLetter); + fill(theCatcode + 'A', theCatcode + 'Z' + 1, catLetter); + + theCatcode[int('\\')] = catEscape; + theCatcode[int('{')] = catBegin; + theCatcode[int('}')] = catEnd; + theCatcode[int('$')] = catMath; + theCatcode[int('&')] = catAlign; + theCatcode[int('\n')] = catNewline; + theCatcode[int('#')] = catParameter; + theCatcode[int('^')] = catSuper; + theCatcode[int('_')] = catSub; + theCatcode[int(0x7f)] = catIgnore; + theCatcode[int(' ')] = catSpace; + theCatcode[int('\t')] = catSpace; + theCatcode[int('\r')] = catNewline; + theCatcode[int('~')] = catActive; + theCatcode[int('%')] = catComment; +} + + +} // namespace lyx diff --git a/src/mathed/MathStream.C b/src/mathed/MathStream.C deleted file mode 100644 index 83c95455e4..0000000000 --- a/src/mathed/MathStream.C +++ /dev/null @@ -1,474 +0,0 @@ -/** - * \file MathStream.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "InsetMath.h" -#include "MathData.h" -#include "MathExtern.h" -#include "MathStream.h" - -#include "support/lyxalgo.h" -#include "support/textutils.h" - - -namespace lyx { - -using std::strlen; - - - - -////////////////////////////////////////////////////////////////////// - - -NormalStream & operator<<(NormalStream & ns, MathAtom const & at) -{ - at->normalize(ns); - return ns; -} - - -NormalStream & operator<<(NormalStream & ns, MathArray const & ar) -{ - normalize(ar, ns); - return ns; -} - - -NormalStream & operator<<(NormalStream & ns, docstring const & s) -{ - ns.os() << s; - return ns; -} - - -NormalStream & operator<<(NormalStream & ns, const std::string & s) -{ - ns.os() << from_utf8(s); - return ns; -} - - -NormalStream & operator<<(NormalStream & ns, char const * s) -{ - ns.os() << s; - return ns; -} - - -NormalStream & operator<<(NormalStream & ns, char c) -{ - ns.os() << c; - return ns; -} - - -NormalStream & operator<<(NormalStream & ns, int i) -{ - ns.os() << i; - return ns; -} - - - -///////////////////////////////////////////////////////////////// - - -WriteStream & operator<<(WriteStream & ws, docstring const & s) -{ - if (ws.pendingSpace() && s.length() > 0) { - if (isAlphaASCII(s[0])) - ws.os() << ' '; - ws.pendingSpace(false); - } - ws.os() << s; - int lf = 0; - docstring::const_iterator dit = s.begin(); - docstring::const_iterator end = s.end(); - for (; dit != end; ++dit) - if ((*dit) == '\n') - ++lf; - ws.addlines(lf); - return ws; -} - - -WriteStream::WriteStream(odocstream & os, bool fragile, bool latex) - : os_(os), fragile_(fragile), firstitem_(false), latex_(latex), - pendingspace_(false), line_(0) -{} - - -WriteStream::WriteStream(odocstream & os) - : os_(os), fragile_(false), firstitem_(false), latex_(false), - pendingspace_(false), line_(0) -{} - - -WriteStream::~WriteStream() -{ - if (pendingspace_) - os_ << ' '; -} - - -void WriteStream::addlines(unsigned int n) -{ - line_ += n; -} - - -void WriteStream::pendingSpace(bool how) -{ - pendingspace_ = how; -} - - -WriteStream & operator<<(WriteStream & ws, MathAtom const & at) -{ - at->write(ws); - return ws; -} - - -WriteStream & operator<<(WriteStream & ws, MathArray const & ar) -{ - write(ar, ws); - return ws; -} - - -WriteStream & operator<<(WriteStream & ws, char const * s) -{ - if (ws.pendingSpace() && strlen(s) > 0) { - if (isAlphaASCII(s[0])) - ws.os() << ' '; - ws.pendingSpace(false); - } - ws.os() << s; - ws.addlines(int(count(s, s + strlen(s), '\n'))); - return ws; -} - - -WriteStream & operator<<(WriteStream & ws, char c) -{ - if (ws.pendingSpace()) { - if (isAlphaASCII(c)) - ws.os() << ' '; - ws.pendingSpace(false); - } - ws.os() << c; - if (c == '\n') - ws.addlines(1); - return ws; -} - - -WriteStream & operator<<(WriteStream & ws, int i) -{ - ws.os() << i; - return ws; -} - - -WriteStream & operator<<(WriteStream & ws, unsigned int i) -{ - ws.os() << i; - return ws; -} - - -////////////////////////////////////////////////////////////////////// - - -MathStream::MathStream(odocstream & os) - : os_(os), tab_(0), line_(0), lastchar_(0) -{} - - -MathStream & operator<<(MathStream & ms, MathAtom const & at) -{ - at->mathmlize(ms); - return ms; -} - - -MathStream & operator<<(MathStream & ms, MathArray const & ar) -{ - mathmlize(ar, ms); - return ms; -} - - -MathStream & operator<<(MathStream & ms, char const * s) -{ - ms.os() << s; - return ms; -} - - -MathStream & operator<<(MathStream & ms, char c) -{ - ms.os() << c; - return ms; -} - - -MathStream & operator<<(MathStream & ms, MTag const & t) -{ - ++ms.tab(); - ms.cr(); - ms.os() << '<' << t.tag_ << '>'; - return ms; -} - - -MathStream & operator<<(MathStream & ms, ETag const & t) -{ - ms.cr(); - if (ms.tab() > 0) - --ms.tab(); - ms.os() << "'; - return ms; -} - - -void MathStream::cr() -{ - os() << '\n'; - for (int i = 0; i < tab(); ++i) - os() << ' '; -} - - -MathStream & operator<<(MathStream & ms, docstring const & s) -{ - ms.os() << s; - return ms; -} - -////////////////////////////////////////////////////////////////////// - - -MapleStream & operator<<(MapleStream & ms, MathAtom const & at) -{ - at->maple(ms); - return ms; -} - - -MapleStream & operator<<(MapleStream & ms, MathArray const & ar) -{ - maple(ar, ms); - return ms; -} - - -MapleStream & operator<<(MapleStream & ms, char const * s) -{ - ms.os() << s; - return ms; -} - - -MapleStream & operator<<(MapleStream & ms, char c) -{ - ms.os() << c; - return ms; -} - - -MapleStream & operator<<(MapleStream & ms, int i) -{ - ms.os() << i; - return ms; -} - - -MapleStream & operator<<(MapleStream & ms, char_type c) -{ - ms.os().put(c); - return ms; -} - - -MapleStream & operator<<(MapleStream & ms, docstring const & s) -{ - ms.os() << s; - return ms; -} - - -////////////////////////////////////////////////////////////////////// - - -MaximaStream & operator<<(MaximaStream & ms, MathAtom const & at) -{ - at->maxima(ms); - return ms; -} - - -MaximaStream & operator<<(MaximaStream & ms, MathArray const & ar) -{ - maxima(ar, ms); - return ms; -} - - -MaximaStream & operator<<(MaximaStream & ms, char const * s) -{ - ms.os() << s; - return ms; -} - - -MaximaStream & operator<<(MaximaStream & ms, char c) -{ - ms.os() << c; - return ms; -} - - -MaximaStream & operator<<(MaximaStream & ms, int i) -{ - ms.os() << i; - return ms; -} - - -MaximaStream & operator<<(MaximaStream & ms, docstring const & s) -{ - ms.os() << s; - return ms; -} - - -MaximaStream & operator<<(MaximaStream & ms, char_type c) -{ - ms.os().put(c); - return ms; -} - - -////////////////////////////////////////////////////////////////////// - - -MathematicaStream & operator<<(MathematicaStream & ms, MathAtom const & at) -{ - at->mathematica(ms); - return ms; -} - - -MathematicaStream & operator<<(MathematicaStream & ms, MathArray const & ar) -{ - mathematica(ar, ms); - return ms; -} - - -MathematicaStream & operator<<(MathematicaStream & ms, char const * s) -{ - ms.os() << s; - return ms; -} - - -MathematicaStream & operator<<(MathematicaStream & ms, char c) -{ - ms.os() << c; - return ms; -} - - -MathematicaStream & operator<<(MathematicaStream & ms, int i) -{ - ms.os() << i; - return ms; -} - - -MathematicaStream & operator<<(MathematicaStream & ms, docstring const & s) -{ - ms.os() << s; - return ms; -} - - -MathematicaStream & operator<<(MathematicaStream & ms, char_type c) -{ - ms.os().put(c); - return ms; -} - - -////////////////////////////////////////////////////////////////////// - - -OctaveStream & operator<<(OctaveStream & ns, MathAtom const & at) -{ - at->octave(ns); - return ns; -} - - -OctaveStream & operator<<(OctaveStream & ns, MathArray const & ar) -{ - octave(ar, ns); - return ns; -} - - -OctaveStream & operator<<(OctaveStream & ns, char const * s) -{ - ns.os() << s; - return ns; -} - - -OctaveStream & operator<<(OctaveStream & ns, char c) -{ - ns.os() << c; - return ns; -} - - -OctaveStream & operator<<(OctaveStream & ns, int i) -{ - ns.os() << i; - return ns; -} - - -OctaveStream & operator<<(OctaveStream & ns, docstring const & s) -{ - ns.os() << s; - return ns; -} - - -OctaveStream & operator<<(OctaveStream & ns, char_type c) -{ - ns.os().put(c); - return ns; -} - - -OctaveStream & operator<<(OctaveStream & os, std::string const & s) -{ - os.os() << from_utf8(s); - return os; -} - - -} // namespace lyx diff --git a/src/mathed/MathStream.cpp b/src/mathed/MathStream.cpp new file mode 100644 index 0000000000..83c95455e4 --- /dev/null +++ b/src/mathed/MathStream.cpp @@ -0,0 +1,474 @@ +/** + * \file MathStream.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMath.h" +#include "MathData.h" +#include "MathExtern.h" +#include "MathStream.h" + +#include "support/lyxalgo.h" +#include "support/textutils.h" + + +namespace lyx { + +using std::strlen; + + + + +////////////////////////////////////////////////////////////////////// + + +NormalStream & operator<<(NormalStream & ns, MathAtom const & at) +{ + at->normalize(ns); + return ns; +} + + +NormalStream & operator<<(NormalStream & ns, MathArray const & ar) +{ + normalize(ar, ns); + return ns; +} + + +NormalStream & operator<<(NormalStream & ns, docstring const & s) +{ + ns.os() << s; + return ns; +} + + +NormalStream & operator<<(NormalStream & ns, const std::string & s) +{ + ns.os() << from_utf8(s); + return ns; +} + + +NormalStream & operator<<(NormalStream & ns, char const * s) +{ + ns.os() << s; + return ns; +} + + +NormalStream & operator<<(NormalStream & ns, char c) +{ + ns.os() << c; + return ns; +} + + +NormalStream & operator<<(NormalStream & ns, int i) +{ + ns.os() << i; + return ns; +} + + + +///////////////////////////////////////////////////////////////// + + +WriteStream & operator<<(WriteStream & ws, docstring const & s) +{ + if (ws.pendingSpace() && s.length() > 0) { + if (isAlphaASCII(s[0])) + ws.os() << ' '; + ws.pendingSpace(false); + } + ws.os() << s; + int lf = 0; + docstring::const_iterator dit = s.begin(); + docstring::const_iterator end = s.end(); + for (; dit != end; ++dit) + if ((*dit) == '\n') + ++lf; + ws.addlines(lf); + return ws; +} + + +WriteStream::WriteStream(odocstream & os, bool fragile, bool latex) + : os_(os), fragile_(fragile), firstitem_(false), latex_(latex), + pendingspace_(false), line_(0) +{} + + +WriteStream::WriteStream(odocstream & os) + : os_(os), fragile_(false), firstitem_(false), latex_(false), + pendingspace_(false), line_(0) +{} + + +WriteStream::~WriteStream() +{ + if (pendingspace_) + os_ << ' '; +} + + +void WriteStream::addlines(unsigned int n) +{ + line_ += n; +} + + +void WriteStream::pendingSpace(bool how) +{ + pendingspace_ = how; +} + + +WriteStream & operator<<(WriteStream & ws, MathAtom const & at) +{ + at->write(ws); + return ws; +} + + +WriteStream & operator<<(WriteStream & ws, MathArray const & ar) +{ + write(ar, ws); + return ws; +} + + +WriteStream & operator<<(WriteStream & ws, char const * s) +{ + if (ws.pendingSpace() && strlen(s) > 0) { + if (isAlphaASCII(s[0])) + ws.os() << ' '; + ws.pendingSpace(false); + } + ws.os() << s; + ws.addlines(int(count(s, s + strlen(s), '\n'))); + return ws; +} + + +WriteStream & operator<<(WriteStream & ws, char c) +{ + if (ws.pendingSpace()) { + if (isAlphaASCII(c)) + ws.os() << ' '; + ws.pendingSpace(false); + } + ws.os() << c; + if (c == '\n') + ws.addlines(1); + return ws; +} + + +WriteStream & operator<<(WriteStream & ws, int i) +{ + ws.os() << i; + return ws; +} + + +WriteStream & operator<<(WriteStream & ws, unsigned int i) +{ + ws.os() << i; + return ws; +} + + +////////////////////////////////////////////////////////////////////// + + +MathStream::MathStream(odocstream & os) + : os_(os), tab_(0), line_(0), lastchar_(0) +{} + + +MathStream & operator<<(MathStream & ms, MathAtom const & at) +{ + at->mathmlize(ms); + return ms; +} + + +MathStream & operator<<(MathStream & ms, MathArray const & ar) +{ + mathmlize(ar, ms); + return ms; +} + + +MathStream & operator<<(MathStream & ms, char const * s) +{ + ms.os() << s; + return ms; +} + + +MathStream & operator<<(MathStream & ms, char c) +{ + ms.os() << c; + return ms; +} + + +MathStream & operator<<(MathStream & ms, MTag const & t) +{ + ++ms.tab(); + ms.cr(); + ms.os() << '<' << t.tag_ << '>'; + return ms; +} + + +MathStream & operator<<(MathStream & ms, ETag const & t) +{ + ms.cr(); + if (ms.tab() > 0) + --ms.tab(); + ms.os() << "'; + return ms; +} + + +void MathStream::cr() +{ + os() << '\n'; + for (int i = 0; i < tab(); ++i) + os() << ' '; +} + + +MathStream & operator<<(MathStream & ms, docstring const & s) +{ + ms.os() << s; + return ms; +} + +////////////////////////////////////////////////////////////////////// + + +MapleStream & operator<<(MapleStream & ms, MathAtom const & at) +{ + at->maple(ms); + return ms; +} + + +MapleStream & operator<<(MapleStream & ms, MathArray const & ar) +{ + maple(ar, ms); + return ms; +} + + +MapleStream & operator<<(MapleStream & ms, char const * s) +{ + ms.os() << s; + return ms; +} + + +MapleStream & operator<<(MapleStream & ms, char c) +{ + ms.os() << c; + return ms; +} + + +MapleStream & operator<<(MapleStream & ms, int i) +{ + ms.os() << i; + return ms; +} + + +MapleStream & operator<<(MapleStream & ms, char_type c) +{ + ms.os().put(c); + return ms; +} + + +MapleStream & operator<<(MapleStream & ms, docstring const & s) +{ + ms.os() << s; + return ms; +} + + +////////////////////////////////////////////////////////////////////// + + +MaximaStream & operator<<(MaximaStream & ms, MathAtom const & at) +{ + at->maxima(ms); + return ms; +} + + +MaximaStream & operator<<(MaximaStream & ms, MathArray const & ar) +{ + maxima(ar, ms); + return ms; +} + + +MaximaStream & operator<<(MaximaStream & ms, char const * s) +{ + ms.os() << s; + return ms; +} + + +MaximaStream & operator<<(MaximaStream & ms, char c) +{ + ms.os() << c; + return ms; +} + + +MaximaStream & operator<<(MaximaStream & ms, int i) +{ + ms.os() << i; + return ms; +} + + +MaximaStream & operator<<(MaximaStream & ms, docstring const & s) +{ + ms.os() << s; + return ms; +} + + +MaximaStream & operator<<(MaximaStream & ms, char_type c) +{ + ms.os().put(c); + return ms; +} + + +////////////////////////////////////////////////////////////////////// + + +MathematicaStream & operator<<(MathematicaStream & ms, MathAtom const & at) +{ + at->mathematica(ms); + return ms; +} + + +MathematicaStream & operator<<(MathematicaStream & ms, MathArray const & ar) +{ + mathematica(ar, ms); + return ms; +} + + +MathematicaStream & operator<<(MathematicaStream & ms, char const * s) +{ + ms.os() << s; + return ms; +} + + +MathematicaStream & operator<<(MathematicaStream & ms, char c) +{ + ms.os() << c; + return ms; +} + + +MathematicaStream & operator<<(MathematicaStream & ms, int i) +{ + ms.os() << i; + return ms; +} + + +MathematicaStream & operator<<(MathematicaStream & ms, docstring const & s) +{ + ms.os() << s; + return ms; +} + + +MathematicaStream & operator<<(MathematicaStream & ms, char_type c) +{ + ms.os().put(c); + return ms; +} + + +////////////////////////////////////////////////////////////////////// + + +OctaveStream & operator<<(OctaveStream & ns, MathAtom const & at) +{ + at->octave(ns); + return ns; +} + + +OctaveStream & operator<<(OctaveStream & ns, MathArray const & ar) +{ + octave(ar, ns); + return ns; +} + + +OctaveStream & operator<<(OctaveStream & ns, char const * s) +{ + ns.os() << s; + return ns; +} + + +OctaveStream & operator<<(OctaveStream & ns, char c) +{ + ns.os() << c; + return ns; +} + + +OctaveStream & operator<<(OctaveStream & ns, int i) +{ + ns.os() << i; + return ns; +} + + +OctaveStream & operator<<(OctaveStream & ns, docstring const & s) +{ + ns.os() << s; + return ns; +} + + +OctaveStream & operator<<(OctaveStream & ns, char_type c) +{ + ns.os().put(c); + return ns; +} + + +OctaveStream & operator<<(OctaveStream & os, std::string const & s) +{ + os.os() << from_utf8(s); + return os; +} + + +} // namespace lyx diff --git a/src/mathed/MathSupport.C b/src/mathed/MathSupport.C deleted file mode 100644 index 8f3aacb66b..0000000000 --- a/src/mathed/MathSupport.C +++ /dev/null @@ -1,714 +0,0 @@ -/** - * \file MathSupport.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Alejandro Aguilar Sierra - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "MathSupport.h" -#include "MathData.h" -#include "InsetMath.h" -#include "MathStream.h" -#include "MathParser.h" - -#include "debug.h" -#include "LColor.h" - -#include "frontends/FontLoader.h" -#include "frontends/FontMetrics.h" -#include "frontends/Painter.h" - -#include -#include - - -namespace lyx { - -using frontend::Painter; - -using std::max; -using std::endl; -using std::vector; - - -/// -class Matrix { -public: - /// - Matrix(int, double, double); - /// - void transform(double &, double &); -private: - /// - double m_[2][2]; -}; - - -Matrix::Matrix(int code, double x, double y) -{ - double const cs = (code & 1) ? 0 : (1 - code); - double const sn = (code & 1) ? (2 - code) : 0; - m_[0][0] = cs * x; - m_[0][1] = sn * x; - m_[1][0] = -sn * y; - m_[1][1] = cs * y; -} - - -void Matrix::transform(double & x, double & y) -{ - double xx = m_[0][0] * x + m_[0][1] * y; - double yy = m_[1][0] * x + m_[1][1] * y; - x = xx; - y = yy; -} - - - -namespace { - -/* - * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is: - * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline - */ - - -double const parenthHigh[] = { - 2, 13, - 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772, - 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300, - 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034, - 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677, - 0.9840, 0.9986, - 0 -}; - - -double const parenth[] = { - 2, 13, - 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126, - 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621, - 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647, - 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412, - 0.9930, 0.9919, - 0 -}; - - -double const brace[] = { - 2, 21, - 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243, - 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278, - 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615, - 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081, - 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268, - 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473, - 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980, - 0 -}; - - -double const arrow[] = { - 4, 7, - 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500, - 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000, - 0.9500, 0.7500, - 3, 0.5000, 0.1500, 0.5000, 0.9500, - 0 -}; - - -double const Arrow[] = { - 4, 7, - 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500, - 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000, - 0.9500, 0.7500, - 3, 0.3500, 0.5000, 0.3500, 0.9500, - 3, 0.6500, 0.5000, 0.6500, 0.9500, - 0 -}; - - -double const udarrow[] = { - 2, 3, - 0.015, 0.25, 0.5, 0.05, 0.95, 0.25, - 2, 3, - 0.015, 0.75, 0.5, 0.95, 0.95, 0.75, - 1, 0.5, 0.2, 0.5, 0.8, - 0 -}; - - -double const Udarrow[] = { - 2, 3, - 0.015, 0.25, 0.5, 0.05, 0.95, 0.25, - 2, 3, - 0.015, 0.75, 0.5, 0.95, 0.95, 0.75, - 1, 0.35, 0.2, 0.35, 0.8, - 1, 0.65, 0.2, 0.65, 0.8, - 0 -}; - - -double const brack[] = { - 2, 4, - 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95, - 0 -}; - - -double const corner[] = { - 2, 3, - 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, - 0 -}; - - -double const angle[] = { - 2, 3, - 1, 0, 0.05, 0.5, 1, 1, - 0 -}; - - -double const slash[] = { - 1, 0.95, 0.05, 0.05, 0.95, - 0 -}; - - -double const hline[] = { - 1, 0.00, 0.5, 1.0, 0.5, - 0 -}; - - -double const ddot[] = { - 1, 0.2, 0.5, 0.3, 0.5, - 1, 0.7, 0.5, 0.8, 0.5, - 0 -}; - - -double const dddot[] = { - 1, 0.1, 0.5, 0.2, 0.5, - 1, 0.45, 0.5, 0.55, 0.5, - 1, 0.8, 0.5, 0.9, 0.5, - 0 -}; - - -double const hline3[] = { - 1, 0.1, 0, 0.15, 0, - 1, 0.475, 0, 0.525, 0, - 1, 0.85, 0, 0.9, 0, - 0 -}; - - -double const dline3[] = { - 1, 0.1, 0.1, 0.15, 0.15, - 1, 0.475, 0.475, 0.525, 0.525, - 1, 0.85, 0.85, 0.9, 0.9, - 0 -}; - - -double const hlinesmall[] = { - 1, 0.4, 0.5, 0.6, 0.5, - 0 -}; - - -double const ring[] = { - 2, 5, - 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8, - 0 -}; - - -double const vert[] = { - 1, 0.5, 0.05, 0.5, 0.95, - 0 -}; - - -double const Vert[] = { - 1, 0.3, 0.05, 0.3, 0.95, - 1, 0.7, 0.05, 0.7, 0.95, - 0 -}; - - -double const tilde[] = { - 2, 4, - 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2, - 0 -}; - - -struct deco_struct { - double const * data; - int angle; -}; - -struct named_deco_struct { - char const * name; - double const * data; - int angle; -}; - -named_deco_struct deco_table[] = { - // Decorations - {"widehat", angle, 3 }, - {"widetilde", tilde, 0 }, - {"underbar", hline, 0 }, - {"underline", hline, 0 }, - {"overline", hline, 0 }, - {"underbrace", brace, 1 }, - {"overbrace", brace, 3 }, - {"overleftarrow", arrow, 1 }, - {"overrightarrow", arrow, 3 }, - {"overleftrightarrow", udarrow, 1 }, - {"xleftarrow", arrow, 1 }, - {"xrightarrow", arrow, 3 }, - {"underleftarrow", arrow, 1 }, - {"underrightarrow", arrow, 3 }, - {"underleftrightarrow", udarrow, 1 }, - - // Delimiters - {"(", parenth, 0 }, - {")", parenth, 2 }, - {"{", brace, 0 }, - {"}", brace, 2 }, - {"lbrace", brace, 0 }, - {"rbrace", brace, 2 }, - {"[", brack, 0 }, - {"]", brack, 2 }, - {"|", vert, 0 }, - {"/", slash, 0 }, - {"slash", slash, 0 }, - {"vert", vert, 0 }, - {"Vert", Vert, 0 }, - {"'", slash, 1 }, - {"\\", slash, 1 }, - {"backslash", slash, 1 }, - {"langle", angle, 0 }, - {"lceil", corner, 0 }, - {"lfloor", corner, 1 }, - {"rangle", angle, 2 }, - {"rceil", corner, 3 }, - {"rfloor", corner, 2 }, - {"downarrow", arrow, 2 }, - {"Downarrow", Arrow, 2 }, - {"uparrow", arrow, 0 }, - {"Uparrow", Arrow, 0 }, - {"updownarrow", udarrow, 0 }, - {"Updownarrow", Udarrow, 0 }, - - // Accents - {"ddot", ddot, 0 }, - {"dddot", dddot, 0 }, - {"hat", angle, 3 }, - {"grave", slash, 1 }, - {"acute", slash, 0 }, - {"tilde", tilde, 0 }, - {"bar", hline, 0 }, - {"dot", hlinesmall, 0 }, - {"check", angle, 1 }, - {"breve", parenth, 1 }, - {"vec", arrow, 3 }, - {"mathring", ring, 0 }, - - // Dots - {"dots", hline3, 0 }, - {"ldots", hline3, 0 }, - {"cdots", hline3, 0 }, - {"vdots", hline3, 1 }, - {"ddots", dline3, 0 }, - {"dotsb", hline3, 0 }, - {"dotsc", hline3, 0 }, - {"dotsi", hline3, 0 }, - {"dotsm", hline3, 0 }, - {"dotso", hline3, 0 } -}; - - -std::map deco_list; - -// sort the table on startup -class init_deco_table { -public: - init_deco_table() { - unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]); - for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) { - deco_struct d; - d.data = p->data; - d.angle = p->angle; - deco_list[from_ascii(p->name)] = d; - } - } -}; - -static init_deco_table dummy; - - -deco_struct const * search_deco(docstring const & name) -{ - std::map::const_iterator p = deco_list.find(name); - return p == deco_list.end() ? 0 : &(p->second); -} - - -} // namespace anon - - -int mathed_char_width(LyXFont const & font, char_type c) -{ - return theFontMetrics(font).width(c); -} - - -int mathed_char_kerning(LyXFont const & font, char_type c) -{ - frontend::FontMetrics const & fm = theFontMetrics(font); - return fm.rbearing(c) - fm.width(c); -} - - -void mathed_string_dim(LyXFont const & font, - docstring const & s, - Dimension & dim) -{ - frontend::FontMetrics const & fm = theFontMetrics(font); - dim.asc = 0; - dim.des = 0; - for (docstring::const_iterator it = s.begin(); - it != s.end(); - ++it) { - dim.asc = max(dim.asc, fm.ascent(*it)); - dim.des = max(dim.des, fm.descent(*it)); - } - dim.wid = fm.width(s); -} - - -int mathed_string_width(LyXFont const & font, docstring const & s) -{ - return theFontMetrics(font).width(s); -} - - -void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h, - docstring const & name) -{ - if (name == ".") { - pi.pain.line(x + w/2, y, x + w/2, y + h, - LColor::cursor, Painter::line_onoffdash); - return; - } - - deco_struct const * mds = search_deco(name); - if (!mds) { - lyxerr << "Deco was not found. Programming error?" << endl; - lyxerr << "name: '" << to_utf8(name) << "'" << endl; - return; - } - - int const n = (w < h) ? w : h; - int const r = mds->angle; - double const * d = mds->data; - - if (h > 70 && (name == "(" || name == ")")) - d = parenthHigh; - - Matrix mt(r, w, h); - Matrix sqmt(r, n, n); - - if (r > 0 && r < 3) - y += h; - - if (r >= 2) - x += w; - - for (int i = 0; d[i]; ) { - int code = int(d[i++]); - if (code & 1) { // code == 1 || code == 3 - double xx = d[i++]; - double yy = d[i++]; - double x2 = d[i++]; - double y2 = d[i++]; - if (code == 3) - sqmt.transform(xx, yy); - else - mt.transform(xx, yy); - mt.transform(x2, y2); - pi.pain.line( - int(x + xx + 0.5), int(y + yy + 0.5), - int(x + x2 + 0.5), int(y + y2 + 0.5), - LColor::math); - } else { - int xp[32]; - int yp[32]; - int const n = int(d[i++]); - for (int j = 0; j < n; ++j) { - double xx = d[i++]; - double yy = d[i++]; -// lyxerr << ' ' << xx << ' ' << yy << ' '; - if (code == 4) - sqmt.transform(xx, yy); - else - mt.transform(xx, yy); - xp[j] = int(x + xx + 0.5); - yp[j] = int(y + yy + 0.5); - // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']'; - } - pi.pain.lines(xp, yp, n, LColor::math); - } - } -} - - -void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str) -{ - LyXFont f = pi.base.font; - f.setColor(LColor::latex); - pi.pain.text(x, y, str, f); -} - - -void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str) -{ - LyXFont f = pi.base.font; - f.setColor(LColor::foreground); - pi.pain.text(x, y, str, f); -} - - -void math_font_max_dim(LyXFont const & font, int & asc, int & des) -{ - frontend::FontMetrics const & fm = theFontMetrics(font); - asc = fm.maxAscent(); - des = fm.maxDescent(); -} - - -struct fontinfo { - std::string cmd_; - LyXFont::FONT_FAMILY family_; - LyXFont::FONT_SERIES series_; - LyXFont::FONT_SHAPE shape_; - LColor::color color_; -}; - - -LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY; -LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES; -LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE; - - -// mathnormal should be the first, otherwise the fallback further down -// does not work -fontinfo fontinfos[] = { - // math fonts - {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES, - LyXFont::ITALIC_SHAPE, LColor::math}, - {"mathbf", inh_family, LyXFont::BOLD_SERIES, - inh_shape, LColor::math}, - {"mathcal", LyXFont::CMSY_FAMILY, inh_series, - inh_shape, LColor::math}, - {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series, - inh_shape, LColor::math}, - {"mathrm", LyXFont::ROMAN_FAMILY, inh_series, - LyXFont::UP_SHAPE, LColor::math}, - {"mathsf", LyXFont::SANS_FAMILY, inh_series, - inh_shape, LColor::math}, - {"mathbb", LyXFont::MSB_FAMILY, inh_series, - inh_shape, LColor::math}, - {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series, - inh_shape, LColor::math}, - {"mathit", inh_family, inh_series, - LyXFont::ITALIC_SHAPE, LColor::math}, - {"cmex", LyXFont::CMEX_FAMILY, inh_series, - inh_shape, LColor::math}, - {"cmm", LyXFont::CMM_FAMILY, inh_series, - inh_shape, LColor::math}, - {"cmr", LyXFont::CMR_FAMILY, inh_series, - inh_shape, LColor::math}, - {"cmsy", LyXFont::CMSY_FAMILY, inh_series, - inh_shape, LColor::math}, - {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series, - inh_shape, LColor::math}, - {"msa", LyXFont::MSA_FAMILY, inh_series, - inh_shape, LColor::math}, - {"msb", LyXFont::MSB_FAMILY, inh_series, - inh_shape, LColor::math}, - {"wasy", LyXFont::WASY_FAMILY, inh_series, - inh_shape, LColor::none}, - {"esint", LyXFont::ESINT_FAMILY, inh_series, - inh_shape, LColor::none}, - - // Text fonts - {"text", inh_family, inh_series, - inh_shape, LColor::foreground}, - {"textbf", inh_family, LyXFont::BOLD_SERIES, - inh_shape, LColor::foreground}, - {"textit", inh_family, inh_series, - LyXFont::ITALIC_SHAPE, LColor::foreground}, - {"textmd", inh_family, LyXFont::MEDIUM_SERIES, - inh_shape, LColor::foreground}, - {"textnormal", inh_family, inh_series, - LyXFont::UP_SHAPE, LColor::foreground}, - {"textrm", LyXFont::ROMAN_FAMILY, - inh_series, LyXFont::UP_SHAPE,LColor::foreground}, - {"textsc", inh_family, inh_series, - LyXFont::SMALLCAPS_SHAPE, LColor::foreground}, - {"textsf", LyXFont::SANS_FAMILY, inh_series, - inh_shape, LColor::foreground}, - {"textsl", inh_family, inh_series, - LyXFont::SLANTED_SHAPE, LColor::foreground}, - {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series, - inh_shape, LColor::foreground}, - {"textup", inh_family, inh_series, - LyXFont::UP_SHAPE, LColor::foreground}, - - // TIPA support - {"textipa", inh_family, inh_series, - inh_shape, LColor::foreground}, - - // LyX internal usage - {"lyxtex", inh_family, inh_series, - LyXFont::UP_SHAPE, LColor::latex}, - {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series, - inh_shape, LColor::math}, - {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES, - inh_shape, LColor::math}, - {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES, - LyXFont::UP_SHAPE, LColor::foreground}, - {"lyxnochange", inh_family, inh_series, - inh_shape, LColor::foreground}, - {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES, - LyXFont::UP_SHAPE, LColor::math}, - {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES, - LyXFont::ITALIC_SHAPE, LColor::math}, - {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES, - LyXFont::ITALIC_SHAPE, LColor::math} -}; - - -fontinfo * lookupFont(docstring const & name0) -{ - //lyxerr << "searching font '" << name << "'" << endl; - int const n = sizeof(fontinfos) / sizeof(fontinfo); - std::string name = to_utf8(name0); - for (int i = 0; i < n; ++i) - if (fontinfos[i].cmd_ == name) { - //lyxerr << "found '" << i << "'" << endl; - return fontinfos + i; - } - return 0; -} - - -fontinfo * searchFont(docstring const & name) -{ - fontinfo * f = lookupFont(name); - return f ? f : fontinfos; - // this should be mathnormal - //return searchFont("mathnormal"); -} - - -bool isFontName(docstring const & name) -{ - return lookupFont(name); -} - - -LyXFont getFont(docstring const & name) -{ - LyXFont font; - augmentFont(font, name); - return font; -} - - -void fakeFont(docstring const & orig, docstring const & fake) -{ - fontinfo * forig = searchFont(orig); - fontinfo * ffake = searchFont(fake); - if (forig && ffake) { - forig->family_ = ffake->family_; - forig->series_ = ffake->series_; - forig->shape_ = ffake->shape_; - forig->color_ = ffake->color_; - } else { - lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '" - << to_utf8(fake) << "'" << endl; - } -} - - -void augmentFont(LyXFont & font, docstring const & name) -{ - static bool initialized = false; - if (!initialized) { - initialized = true; - // fake fonts if necessary - if (!theFontLoader().available(getFont(from_ascii("mathfrak")))) - fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak")); - if (!theFontLoader().available(getFont(from_ascii("mathcal")))) - fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal")); - } - fontinfo * info = searchFont(name); - if (info->family_ != inh_family) - font.setFamily(info->family_); - if (info->series_ != inh_series) - font.setSeries(info->series_); - if (info->shape_ != inh_shape) - font.setShape(info->shape_); - if (info->color_ != LColor::none) - font.setColor(info->color_); -} - - -docstring asString(MathArray const & ar) -{ - odocstringstream os; - WriteStream ws(os); - ws << ar; - return os.str(); -} - - -void asArray(docstring const & str, MathArray & ar) -{ - mathed_parse_cell(ar, str); -} - - -docstring asString(InsetMath const & inset) -{ - odocstringstream os; - WriteStream ws(os); - inset.write(ws); - return os.str(); -} - - -docstring asString(MathAtom const & at) -{ - odocstringstream os; - WriteStream ws(os); - at->write(ws); - return os.str(); -} - - -} // namespace lyx diff --git a/src/mathed/MathSupport.cpp b/src/mathed/MathSupport.cpp new file mode 100644 index 0000000000..8f3aacb66b --- /dev/null +++ b/src/mathed/MathSupport.cpp @@ -0,0 +1,714 @@ +/** + * \file MathSupport.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Alejandro Aguilar Sierra + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "MathSupport.h" +#include "MathData.h" +#include "InsetMath.h" +#include "MathStream.h" +#include "MathParser.h" + +#include "debug.h" +#include "LColor.h" + +#include "frontends/FontLoader.h" +#include "frontends/FontMetrics.h" +#include "frontends/Painter.h" + +#include +#include + + +namespace lyx { + +using frontend::Painter; + +using std::max; +using std::endl; +using std::vector; + + +/// +class Matrix { +public: + /// + Matrix(int, double, double); + /// + void transform(double &, double &); +private: + /// + double m_[2][2]; +}; + + +Matrix::Matrix(int code, double x, double y) +{ + double const cs = (code & 1) ? 0 : (1 - code); + double const sn = (code & 1) ? (2 - code) : 0; + m_[0][0] = cs * x; + m_[0][1] = sn * x; + m_[1][0] = -sn * y; + m_[1][1] = cs * y; +} + + +void Matrix::transform(double & x, double & y) +{ + double xx = m_[0][0] * x + m_[0][1] * y; + double yy = m_[1][0] * x + m_[1][1] * y; + x = xx; + y = yy; +} + + + +namespace { + +/* + * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is: + * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline + */ + + +double const parenthHigh[] = { + 2, 13, + 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772, + 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300, + 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034, + 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677, + 0.9840, 0.9986, + 0 +}; + + +double const parenth[] = { + 2, 13, + 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126, + 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621, + 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647, + 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412, + 0.9930, 0.9919, + 0 +}; + + +double const brace[] = { + 2, 21, + 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243, + 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278, + 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615, + 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081, + 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268, + 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473, + 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980, + 0 +}; + + +double const arrow[] = { + 4, 7, + 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500, + 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000, + 0.9500, 0.7500, + 3, 0.5000, 0.1500, 0.5000, 0.9500, + 0 +}; + + +double const Arrow[] = { + 4, 7, + 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500, + 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000, + 0.9500, 0.7500, + 3, 0.3500, 0.5000, 0.3500, 0.9500, + 3, 0.6500, 0.5000, 0.6500, 0.9500, + 0 +}; + + +double const udarrow[] = { + 2, 3, + 0.015, 0.25, 0.5, 0.05, 0.95, 0.25, + 2, 3, + 0.015, 0.75, 0.5, 0.95, 0.95, 0.75, + 1, 0.5, 0.2, 0.5, 0.8, + 0 +}; + + +double const Udarrow[] = { + 2, 3, + 0.015, 0.25, 0.5, 0.05, 0.95, 0.25, + 2, 3, + 0.015, 0.75, 0.5, 0.95, 0.95, 0.75, + 1, 0.35, 0.2, 0.35, 0.8, + 1, 0.65, 0.2, 0.65, 0.8, + 0 +}; + + +double const brack[] = { + 2, 4, + 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95, + 0 +}; + + +double const corner[] = { + 2, 3, + 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, + 0 +}; + + +double const angle[] = { + 2, 3, + 1, 0, 0.05, 0.5, 1, 1, + 0 +}; + + +double const slash[] = { + 1, 0.95, 0.05, 0.05, 0.95, + 0 +}; + + +double const hline[] = { + 1, 0.00, 0.5, 1.0, 0.5, + 0 +}; + + +double const ddot[] = { + 1, 0.2, 0.5, 0.3, 0.5, + 1, 0.7, 0.5, 0.8, 0.5, + 0 +}; + + +double const dddot[] = { + 1, 0.1, 0.5, 0.2, 0.5, + 1, 0.45, 0.5, 0.55, 0.5, + 1, 0.8, 0.5, 0.9, 0.5, + 0 +}; + + +double const hline3[] = { + 1, 0.1, 0, 0.15, 0, + 1, 0.475, 0, 0.525, 0, + 1, 0.85, 0, 0.9, 0, + 0 +}; + + +double const dline3[] = { + 1, 0.1, 0.1, 0.15, 0.15, + 1, 0.475, 0.475, 0.525, 0.525, + 1, 0.85, 0.85, 0.9, 0.9, + 0 +}; + + +double const hlinesmall[] = { + 1, 0.4, 0.5, 0.6, 0.5, + 0 +}; + + +double const ring[] = { + 2, 5, + 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8, + 0 +}; + + +double const vert[] = { + 1, 0.5, 0.05, 0.5, 0.95, + 0 +}; + + +double const Vert[] = { + 1, 0.3, 0.05, 0.3, 0.95, + 1, 0.7, 0.05, 0.7, 0.95, + 0 +}; + + +double const tilde[] = { + 2, 4, + 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2, + 0 +}; + + +struct deco_struct { + double const * data; + int angle; +}; + +struct named_deco_struct { + char const * name; + double const * data; + int angle; +}; + +named_deco_struct deco_table[] = { + // Decorations + {"widehat", angle, 3 }, + {"widetilde", tilde, 0 }, + {"underbar", hline, 0 }, + {"underline", hline, 0 }, + {"overline", hline, 0 }, + {"underbrace", brace, 1 }, + {"overbrace", brace, 3 }, + {"overleftarrow", arrow, 1 }, + {"overrightarrow", arrow, 3 }, + {"overleftrightarrow", udarrow, 1 }, + {"xleftarrow", arrow, 1 }, + {"xrightarrow", arrow, 3 }, + {"underleftarrow", arrow, 1 }, + {"underrightarrow", arrow, 3 }, + {"underleftrightarrow", udarrow, 1 }, + + // Delimiters + {"(", parenth, 0 }, + {")", parenth, 2 }, + {"{", brace, 0 }, + {"}", brace, 2 }, + {"lbrace", brace, 0 }, + {"rbrace", brace, 2 }, + {"[", brack, 0 }, + {"]", brack, 2 }, + {"|", vert, 0 }, + {"/", slash, 0 }, + {"slash", slash, 0 }, + {"vert", vert, 0 }, + {"Vert", Vert, 0 }, + {"'", slash, 1 }, + {"\\", slash, 1 }, + {"backslash", slash, 1 }, + {"langle", angle, 0 }, + {"lceil", corner, 0 }, + {"lfloor", corner, 1 }, + {"rangle", angle, 2 }, + {"rceil", corner, 3 }, + {"rfloor", corner, 2 }, + {"downarrow", arrow, 2 }, + {"Downarrow", Arrow, 2 }, + {"uparrow", arrow, 0 }, + {"Uparrow", Arrow, 0 }, + {"updownarrow", udarrow, 0 }, + {"Updownarrow", Udarrow, 0 }, + + // Accents + {"ddot", ddot, 0 }, + {"dddot", dddot, 0 }, + {"hat", angle, 3 }, + {"grave", slash, 1 }, + {"acute", slash, 0 }, + {"tilde", tilde, 0 }, + {"bar", hline, 0 }, + {"dot", hlinesmall, 0 }, + {"check", angle, 1 }, + {"breve", parenth, 1 }, + {"vec", arrow, 3 }, + {"mathring", ring, 0 }, + + // Dots + {"dots", hline3, 0 }, + {"ldots", hline3, 0 }, + {"cdots", hline3, 0 }, + {"vdots", hline3, 1 }, + {"ddots", dline3, 0 }, + {"dotsb", hline3, 0 }, + {"dotsc", hline3, 0 }, + {"dotsi", hline3, 0 }, + {"dotsm", hline3, 0 }, + {"dotso", hline3, 0 } +}; + + +std::map deco_list; + +// sort the table on startup +class init_deco_table { +public: + init_deco_table() { + unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]); + for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) { + deco_struct d; + d.data = p->data; + d.angle = p->angle; + deco_list[from_ascii(p->name)] = d; + } + } +}; + +static init_deco_table dummy; + + +deco_struct const * search_deco(docstring const & name) +{ + std::map::const_iterator p = deco_list.find(name); + return p == deco_list.end() ? 0 : &(p->second); +} + + +} // namespace anon + + +int mathed_char_width(LyXFont const & font, char_type c) +{ + return theFontMetrics(font).width(c); +} + + +int mathed_char_kerning(LyXFont const & font, char_type c) +{ + frontend::FontMetrics const & fm = theFontMetrics(font); + return fm.rbearing(c) - fm.width(c); +} + + +void mathed_string_dim(LyXFont const & font, + docstring const & s, + Dimension & dim) +{ + frontend::FontMetrics const & fm = theFontMetrics(font); + dim.asc = 0; + dim.des = 0; + for (docstring::const_iterator it = s.begin(); + it != s.end(); + ++it) { + dim.asc = max(dim.asc, fm.ascent(*it)); + dim.des = max(dim.des, fm.descent(*it)); + } + dim.wid = fm.width(s); +} + + +int mathed_string_width(LyXFont const & font, docstring const & s) +{ + return theFontMetrics(font).width(s); +} + + +void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h, + docstring const & name) +{ + if (name == ".") { + pi.pain.line(x + w/2, y, x + w/2, y + h, + LColor::cursor, Painter::line_onoffdash); + return; + } + + deco_struct const * mds = search_deco(name); + if (!mds) { + lyxerr << "Deco was not found. Programming error?" << endl; + lyxerr << "name: '" << to_utf8(name) << "'" << endl; + return; + } + + int const n = (w < h) ? w : h; + int const r = mds->angle; + double const * d = mds->data; + + if (h > 70 && (name == "(" || name == ")")) + d = parenthHigh; + + Matrix mt(r, w, h); + Matrix sqmt(r, n, n); + + if (r > 0 && r < 3) + y += h; + + if (r >= 2) + x += w; + + for (int i = 0; d[i]; ) { + int code = int(d[i++]); + if (code & 1) { // code == 1 || code == 3 + double xx = d[i++]; + double yy = d[i++]; + double x2 = d[i++]; + double y2 = d[i++]; + if (code == 3) + sqmt.transform(xx, yy); + else + mt.transform(xx, yy); + mt.transform(x2, y2); + pi.pain.line( + int(x + xx + 0.5), int(y + yy + 0.5), + int(x + x2 + 0.5), int(y + y2 + 0.5), + LColor::math); + } else { + int xp[32]; + int yp[32]; + int const n = int(d[i++]); + for (int j = 0; j < n; ++j) { + double xx = d[i++]; + double yy = d[i++]; +// lyxerr << ' ' << xx << ' ' << yy << ' '; + if (code == 4) + sqmt.transform(xx, yy); + else + mt.transform(xx, yy); + xp[j] = int(x + xx + 0.5); + yp[j] = int(y + yy + 0.5); + // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']'; + } + pi.pain.lines(xp, yp, n, LColor::math); + } + } +} + + +void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str) +{ + LyXFont f = pi.base.font; + f.setColor(LColor::latex); + pi.pain.text(x, y, str, f); +} + + +void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str) +{ + LyXFont f = pi.base.font; + f.setColor(LColor::foreground); + pi.pain.text(x, y, str, f); +} + + +void math_font_max_dim(LyXFont const & font, int & asc, int & des) +{ + frontend::FontMetrics const & fm = theFontMetrics(font); + asc = fm.maxAscent(); + des = fm.maxDescent(); +} + + +struct fontinfo { + std::string cmd_; + LyXFont::FONT_FAMILY family_; + LyXFont::FONT_SERIES series_; + LyXFont::FONT_SHAPE shape_; + LColor::color color_; +}; + + +LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY; +LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES; +LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE; + + +// mathnormal should be the first, otherwise the fallback further down +// does not work +fontinfo fontinfos[] = { + // math fonts + {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES, + LyXFont::ITALIC_SHAPE, LColor::math}, + {"mathbf", inh_family, LyXFont::BOLD_SERIES, + inh_shape, LColor::math}, + {"mathcal", LyXFont::CMSY_FAMILY, inh_series, + inh_shape, LColor::math}, + {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series, + inh_shape, LColor::math}, + {"mathrm", LyXFont::ROMAN_FAMILY, inh_series, + LyXFont::UP_SHAPE, LColor::math}, + {"mathsf", LyXFont::SANS_FAMILY, inh_series, + inh_shape, LColor::math}, + {"mathbb", LyXFont::MSB_FAMILY, inh_series, + inh_shape, LColor::math}, + {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series, + inh_shape, LColor::math}, + {"mathit", inh_family, inh_series, + LyXFont::ITALIC_SHAPE, LColor::math}, + {"cmex", LyXFont::CMEX_FAMILY, inh_series, + inh_shape, LColor::math}, + {"cmm", LyXFont::CMM_FAMILY, inh_series, + inh_shape, LColor::math}, + {"cmr", LyXFont::CMR_FAMILY, inh_series, + inh_shape, LColor::math}, + {"cmsy", LyXFont::CMSY_FAMILY, inh_series, + inh_shape, LColor::math}, + {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series, + inh_shape, LColor::math}, + {"msa", LyXFont::MSA_FAMILY, inh_series, + inh_shape, LColor::math}, + {"msb", LyXFont::MSB_FAMILY, inh_series, + inh_shape, LColor::math}, + {"wasy", LyXFont::WASY_FAMILY, inh_series, + inh_shape, LColor::none}, + {"esint", LyXFont::ESINT_FAMILY, inh_series, + inh_shape, LColor::none}, + + // Text fonts + {"text", inh_family, inh_series, + inh_shape, LColor::foreground}, + {"textbf", inh_family, LyXFont::BOLD_SERIES, + inh_shape, LColor::foreground}, + {"textit", inh_family, inh_series, + LyXFont::ITALIC_SHAPE, LColor::foreground}, + {"textmd", inh_family, LyXFont::MEDIUM_SERIES, + inh_shape, LColor::foreground}, + {"textnormal", inh_family, inh_series, + LyXFont::UP_SHAPE, LColor::foreground}, + {"textrm", LyXFont::ROMAN_FAMILY, + inh_series, LyXFont::UP_SHAPE,LColor::foreground}, + {"textsc", inh_family, inh_series, + LyXFont::SMALLCAPS_SHAPE, LColor::foreground}, + {"textsf", LyXFont::SANS_FAMILY, inh_series, + inh_shape, LColor::foreground}, + {"textsl", inh_family, inh_series, + LyXFont::SLANTED_SHAPE, LColor::foreground}, + {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series, + inh_shape, LColor::foreground}, + {"textup", inh_family, inh_series, + LyXFont::UP_SHAPE, LColor::foreground}, + + // TIPA support + {"textipa", inh_family, inh_series, + inh_shape, LColor::foreground}, + + // LyX internal usage + {"lyxtex", inh_family, inh_series, + LyXFont::UP_SHAPE, LColor::latex}, + {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series, + inh_shape, LColor::math}, + {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES, + inh_shape, LColor::math}, + {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES, + LyXFont::UP_SHAPE, LColor::foreground}, + {"lyxnochange", inh_family, inh_series, + inh_shape, LColor::foreground}, + {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES, + LyXFont::UP_SHAPE, LColor::math}, + {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES, + LyXFont::ITALIC_SHAPE, LColor::math}, + {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES, + LyXFont::ITALIC_SHAPE, LColor::math} +}; + + +fontinfo * lookupFont(docstring const & name0) +{ + //lyxerr << "searching font '" << name << "'" << endl; + int const n = sizeof(fontinfos) / sizeof(fontinfo); + std::string name = to_utf8(name0); + for (int i = 0; i < n; ++i) + if (fontinfos[i].cmd_ == name) { + //lyxerr << "found '" << i << "'" << endl; + return fontinfos + i; + } + return 0; +} + + +fontinfo * searchFont(docstring const & name) +{ + fontinfo * f = lookupFont(name); + return f ? f : fontinfos; + // this should be mathnormal + //return searchFont("mathnormal"); +} + + +bool isFontName(docstring const & name) +{ + return lookupFont(name); +} + + +LyXFont getFont(docstring const & name) +{ + LyXFont font; + augmentFont(font, name); + return font; +} + + +void fakeFont(docstring const & orig, docstring const & fake) +{ + fontinfo * forig = searchFont(orig); + fontinfo * ffake = searchFont(fake); + if (forig && ffake) { + forig->family_ = ffake->family_; + forig->series_ = ffake->series_; + forig->shape_ = ffake->shape_; + forig->color_ = ffake->color_; + } else { + lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '" + << to_utf8(fake) << "'" << endl; + } +} + + +void augmentFont(LyXFont & font, docstring const & name) +{ + static bool initialized = false; + if (!initialized) { + initialized = true; + // fake fonts if necessary + if (!theFontLoader().available(getFont(from_ascii("mathfrak")))) + fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak")); + if (!theFontLoader().available(getFont(from_ascii("mathcal")))) + fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal")); + } + fontinfo * info = searchFont(name); + if (info->family_ != inh_family) + font.setFamily(info->family_); + if (info->series_ != inh_series) + font.setSeries(info->series_); + if (info->shape_ != inh_shape) + font.setShape(info->shape_); + if (info->color_ != LColor::none) + font.setColor(info->color_); +} + + +docstring asString(MathArray const & ar) +{ + odocstringstream os; + WriteStream ws(os); + ws << ar; + return os.str(); +} + + +void asArray(docstring const & str, MathArray & ar) +{ + mathed_parse_cell(ar, str); +} + + +docstring asString(InsetMath const & inset) +{ + odocstringstream os; + WriteStream ws(os); + inset.write(ws); + return os.str(); +} + + +docstring asString(MathAtom const & at) +{ + odocstringstream os; + WriteStream ws(os); + at->write(ws); + return os.str(); +} + + +} // namespace lyx diff --git a/src/mathed/TextPainter.C b/src/mathed/TextPainter.C deleted file mode 100644 index fa8ca9944f..0000000000 --- a/src/mathed/TextPainter.C +++ /dev/null @@ -1,81 +0,0 @@ -/** - * \file TextPainter.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author André Pönitz - * - * Full author contact details are available in file CREDITS. - */ - -#include - -#include "TextPainter.h" -#include "support/std_ostream.h" - - -namespace lyx { - - -TextPainter::TextPainter(int xmax, int ymax) - : xmax_(xmax), ymax_(ymax), data_(xmax_ * (ymax_ + 1), ' ') -{} - - -char_type & TextPainter::at(int x, int y) -{ - return data_[y * xmax_ + x]; -} - - -char_type TextPainter::at(int x, int y) const -{ - return data_[y * xmax_ + x]; -} - - -void TextPainter::draw(int x, int y, char_type const * str) -{ - //cerr << "drawing string '" << str << "' at " << x << ',' << y << endl; - for (int i = 0; *str && x + i < xmax_; ++i, ++str) - at(x + i, y) = *str; - //show(); -} - - -void TextPainter::horizontalLine(int x, int y, int n, char_type c) -{ - for (int i = 0; i < n && i + x < xmax_; ++i) - at(x + i, y) = c; -} - - -void TextPainter::verticalLine(int x, int y, int n, char_type c) -{ - for (int i = 0; i < n && i + y < ymax_; ++i) - at(x, y + i) = c; -} - - -void TextPainter::draw(int x, int y, char_type c) -{ - //cerr << "drawing char '" << c << "' at " << x << ',' << y << endl; - at(x, y) = c; - //show(); -} - - -void TextPainter::show(odocstream & os, int offset) const -{ - os << '\n'; - for (int j = 0; j <= ymax_; ++j) { - for (int i = 0; i < offset; ++i) - os << ' '; - for (int i = 0; i < xmax_; ++i) - os << at(i, j); - os << '\n'; - } -} - - -} // namespace lyx diff --git a/src/mathed/TextPainter.cpp b/src/mathed/TextPainter.cpp new file mode 100644 index 0000000000..fa8ca9944f --- /dev/null +++ b/src/mathed/TextPainter.cpp @@ -0,0 +1,81 @@ +/** + * \file TextPainter.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "TextPainter.h" +#include "support/std_ostream.h" + + +namespace lyx { + + +TextPainter::TextPainter(int xmax, int ymax) + : xmax_(xmax), ymax_(ymax), data_(xmax_ * (ymax_ + 1), ' ') +{} + + +char_type & TextPainter::at(int x, int y) +{ + return data_[y * xmax_ + x]; +} + + +char_type TextPainter::at(int x, int y) const +{ + return data_[y * xmax_ + x]; +} + + +void TextPainter::draw(int x, int y, char_type const * str) +{ + //cerr << "drawing string '" << str << "' at " << x << ',' << y << endl; + for (int i = 0; *str && x + i < xmax_; ++i, ++str) + at(x + i, y) = *str; + //show(); +} + + +void TextPainter::horizontalLine(int x, int y, int n, char_type c) +{ + for (int i = 0; i < n && i + x < xmax_; ++i) + at(x + i, y) = c; +} + + +void TextPainter::verticalLine(int x, int y, int n, char_type c) +{ + for (int i = 0; i < n && i + y < ymax_; ++i) + at(x, y + i) = c; +} + + +void TextPainter::draw(int x, int y, char_type c) +{ + //cerr << "drawing char '" << c << "' at " << x << ',' << y << endl; + at(x, y) = c; + //show(); +} + + +void TextPainter::show(odocstream & os, int offset) const +{ + os << '\n'; + for (int j = 0; j <= ymax_; ++j) { + for (int i = 0; i < offset; ++i) + os << ' '; + for (int i = 0; i < xmax_; ++i) + os << at(i, j); + os << '\n'; + } +} + + +} // namespace lyx