Support units in external inset bbox

This brings the external inset on par with the graphics insets as far as the
clipping option is concerned. The graphicxs package supports both: A bounding
box without units (which means that bp ia assumed), and a bounding box with
units, so we can simply output the values including the units.
This commit is contained in:
Georg Baum 2015-07-16 22:04:08 +02:00
parent c11c4fd767
commit 81e592603d
29 changed files with 217 additions and 89 deletions

View File

@ -85,7 +85,7 @@ format_relation = [("0_06", [200], minor_versions("0.6" , 4)),
("1_6", list(range(277,346)), minor_versions("1.6" , 10)),
("2_0", list(range(346,414)), minor_versions("2.0" , 8)),
("2_1", list(range(414,475)), minor_versions("2.1" , 0)),
("2_2", list(range(475,497)), minor_versions("2.2" , 0))
("2_2", list(range(475,498)), minor_versions("2.2" , 0))
]
####################################################################

View File

@ -59,6 +59,7 @@ latex_length(slen):
'''
import re
import string
from parser_tools import find_token, find_end_of_inset
from unicode_symbols import unicode_reps
@ -323,6 +324,44 @@ def latex_length(slen):
return (percent, slen)
def length_in_bp(length):
" Convert a length in LyX format to its value in bp units "
em_width = 10.0 / 72.27 # assume 10pt font size
text_width = 8.27 / 1.7 # assume A4 with default margins
# scale factors are taken from Length::inInch()
scales = {"bp" : 1.0,
"cc" : (72.0 / (72.27 / (12.0 * 0.376 * 2.845))),
"cm" : (72.0 / 2.54),
"dd" : (72.0 / (72.27 / (0.376 * 2.845))),
"em" : (72.0 * em_width),
"ex" : (72.0 * em_width * 0.4305),
"in" : 72.0,
"mm" : (72.0 / 25.4),
"mu" : (72.0 * em_width / 18.0),
"pc" : (72.0 / (72.27 / 12.0)),
"pt" : (72.0 / (72.27)),
"sp" : (72.0 / (72.27 * 65536.0)),
"text%" : (72.0 * text_width / 100.0),
"col%" : (72.0 * text_width / 100.0), # assume 1 column
"page%" : (72.0 * text_width * 1.7 / 100.0),
"line%" : (72.0 * text_width / 100.0),
"theight%" : (72.0 * text_width * 1.787 / 100.0),
"pheight%" : (72.0 * text_width * 2.2 / 100.0)}
rx = re.compile(r'^\s*([^a-zA-Z%]+)([a-zA-Z%]+)\s*$')
m = rx.match(length)
if not m:
document.warning("Invalid length value: " + length + ".")
return 0
value = m.group(1)
unit = m.group(2)
if not unit in scales.keys():
document.warning("Unknown length unit: " + unit + ".")
return value
return "%g" % (float(value) * scales[unit])
def revert_flex_inset(lines, name, LaTeXname):
" Convert flex insets to TeX code "
i = 0

View File

@ -30,7 +30,8 @@ import sys, os
# find_token_backwards, is_in_inset, get_value, get_quoted_value, \
# del_token, check_token, get_option_value
from lyx2lyx_tools import add_to_preamble, put_cmd_in_ert, lyx2latex#, \
from lyx2lyx_tools import add_to_preamble, put_cmd_in_ert, lyx2latex, \
length_in_bp#, \
# insert_to_preamble, latex_length, revert_flex_inset, \
# revert_font_attrs, hex2ratio, str2bool
@ -1527,6 +1528,44 @@ def convert_nounzip(document):
i = j + 1
def convert_revert_external_bbox(document, forward):
" add units to bounding box of external insets "
rx = re.compile(r'^\s*boundingBox\s+\S+\s+\S+\s+\S+\s+\S+\s*$')
i = 0
while True:
i = find_token(document.body, "\\begin_inset External", i)
if i == -1:
break
j = find_end_of_inset(document.body, i)
if j == -1:
document.warning("Malformed LyX document: Can't find end of external inset at line " + str(i))
i += 1
continue
k = find_re(document.body, rx, i, j)
if k == -1:
i = j + 1
continue
tokens = document.body[k].split()
if forward:
for t in range(1, 5):
tokens[t] += "bp"
else:
for t in range(1, 5):
tokens[t] = length_in_bp(tokens[t])
document.body[k] = "\tboundingBox " + tokens[1] + " " + tokens[2] + " " + \
tokens[3] + " " + tokens[4]
i = j + 1
def convert_external_bbox(document):
convert_revert_external_bbox(document, True)
def revert_external_bbox(document):
convert_revert_external_bbox(document, False)
##
# Conversion hub
#
@ -1557,10 +1596,12 @@ convert = [
[493, []],
[494, []],
[495, [convert_subref]],
[496, [convert_nounzip]]
[496, [convert_nounzip]],
[497, [convert_external_bbox]]
]
revert = [
[496, [revert_external_bbox]],
[495, []], # nothing to do since the noUnzip parameter was optional
[494, [revert_subref]],
[493, [revert_jss]],

View File

@ -140,6 +140,14 @@ GuiExternal::GuiExternal(GuiView & lv)
connect(ytED, SIGNAL(textChanged(QString)), this, SLOT(bbChanged()));
connect(xlED, SIGNAL(textChanged(QString)), this, SLOT(bbChanged()));
connect(ybED, SIGNAL(textChanged(QString)), this, SLOT(bbChanged()));
connect(xrUnitCO, SIGNAL(selectionChanged(lyx::Length::UNIT)),
this, SLOT(bbChanged()));
connect(ytUnitCO, SIGNAL(selectionChanged(lyx::Length::UNIT)),
this, SLOT(bbChanged()));
connect(xlUnitCO, SIGNAL(selectionChanged(lyx::Length::UNIT)),
this, SLOT(bbChanged()));
connect(ybUnitCO, SIGNAL(selectionChanged(lyx::Length::UNIT)),
this, SLOT(bbChanged()));
connect(draftCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
QIntValidator * validator = new QIntValidator(displayscaleED);
@ -148,10 +156,10 @@ GuiExternal::GuiExternal(GuiView & lv)
angleED->setValidator(new QDoubleValidator(-360, 360, 2, angleED));
xlED->setValidator(new QIntValidator(xlED));
ybED->setValidator(new QIntValidator(ybED));
xrED->setValidator(new QIntValidator(xrED));
ytED->setValidator(new QIntValidator(ytED));
xlED->setValidator(unsignedLengthValidator(xlED));
ybED->setValidator(unsignedLengthValidator(ybED));
xrED->setValidator(unsignedLengthValidator(xrED));
ytED->setValidator(unsignedLengthValidator(ytED));
widthED->setValidator(unsignedLengthValidator(widthED));
heightED->setValidator(unsignedLengthValidator(heightED));
@ -183,6 +191,10 @@ GuiExternal::GuiExternal(GuiView & lv)
bc().addReadOnly(xlED);
bc().addReadOnly(xrED);
bc().addReadOnly(ybED);
bc().addReadOnly(ytUnitCO);
bc().addReadOnly(xlUnitCO);
bc().addReadOnly(xrUnitCO);
bc().addReadOnly(ybUnitCO);
bc().addReadOnly(extraFormatCO);
bc().addReadOnly(extraED);
@ -318,10 +330,15 @@ void GuiExternal::getbbClicked()
bb = "0 0 " + convert<string>(width) + ' ' + convert<string>(height);
}
xlED->setText(toqstr(token(bb, ' ', 0)));
ybED->setText(toqstr(token(bb, ' ', 1)));
xrED->setText(toqstr(token(bb, ' ', 2)));
ytED->setText(toqstr(token(bb, ' ', 3)));
doubleToWidget(xlED, token(bb, ' ', 0));
doubleToWidget(ybED, token(bb, ' ', 1));
doubleToWidget(xrED, token(bb, ' ', 2));
doubleToWidget(ytED, token(bb, ' ', 3));
// the values from the file always have the bigpoint-unit bp
xlUnitCO->setCurrentIndex(0);
ybUnitCO->setCurrentIndex(0);
xrUnitCO->setCurrentIndex(0);
ytUnitCO->setCurrentIndex(0);
bbChanged_ = false;
}
@ -429,14 +446,17 @@ static void getSize(external::ResizeData & data,
void setCrop(QCheckBox & clipCB,
QLineEdit & xlED, QLineEdit & ybED,
QLineEdit & xrED, QLineEdit & ytED,
LengthCombo & xlUnitCO, LengthCombo & ybUnitCO,
LengthCombo & xrUnitCO, LengthCombo & ytUnitCO,
external::ClipData const & data)
{
clipCB.setChecked(data.clip);
graphics::BoundingBox const & bbox = data.bbox;
xlED.setText(QString::number(bbox.xl));
ybED.setText(QString::number(bbox.yb));
xrED.setText(QString::number(bbox.xr));
ytED.setText(QString::number(bbox.yt));
Length::UNIT const default_unit = data.bbox.xl.zero() ?
Length::defaultUnit() : data.bbox.xl.unit();
lengthToWidgets(&xlED, &xlUnitCO, data.bbox.xl, default_unit);
lengthToWidgets(&ybED, &ybUnitCO, data.bbox.yb, default_unit);
lengthToWidgets(&xrED, &xrUnitCO, data.bbox.xr, default_unit);
lengthToWidgets(&ytED, &ytUnitCO, data.bbox.yt, default_unit);
}
@ -444,6 +464,8 @@ static void getCrop(external::ClipData & data,
QCheckBox const & clipCB,
QLineEdit const & xlED, QLineEdit const & ybED,
QLineEdit const & xrED, QLineEdit const & ytED,
LengthCombo const & xlUnitCO, LengthCombo const & ybUnitCO,
LengthCombo const & xrUnitCO, LengthCombo const & ytUnitCO,
bool bb_changed)
{
data.clip = clipCB.isChecked();
@ -451,10 +473,10 @@ static void getCrop(external::ClipData & data,
if (!bb_changed)
return;
data.bbox.xl = xlED.text().toInt();
data.bbox.yb = ybED.text().toInt();
data.bbox.xr = xrED.text().toInt();
data.bbox.yt = ytED.text().toInt();
data.bbox.xl = Length(widgetsToLength(&xlED, &xlUnitCO));
data.bbox.yb = Length(widgetsToLength(&ybED, &ybUnitCO));
data.bbox.xr = Length(widgetsToLength(&xrED, &xrUnitCO));
data.bbox.yt = Length(widgetsToLength(&ytED, &ytUnitCO));
}
@ -494,7 +516,8 @@ void GuiExternal::updateContents()
setSize(*widthED, *widthUnitCO, *heightED, *heightUnitCO,
*aspectratioCB, params_.resizedata);
setCrop(*clipCB, *xlED, *ybED, *xrED, *ytED, params_.clipdata);
setCrop(*clipCB, *xlED, *ybED, *xrED, *ytED,
*xlUnitCO, *ybUnitCO, *xrUnitCO, *ytUnitCO, params_.clipdata);
bbChanged_ = !params_.clipdata.bbox.empty();
isValid();
@ -584,8 +607,8 @@ void GuiExternal::applyView()
*heightED, *heightUnitCO, *aspectratioCB, usingScale());
if (cropGB->isEnabled())
getCrop(params_.clipdata, *clipCB, *xlED, *ybED,
*xrED, *ytED, bbChanged_);
getCrop(params_.clipdata, *clipCB, *xlED, *ybED, *xrED, *ytED,
*xlUnitCO, *ybUnitCO, *xrUnitCO, *ytUnitCO, bbChanged_);
if (optionsGB->isEnabled()) {
MapType::const_iterator it = extra_.begin();

View File

@ -143,11 +143,11 @@ bool GuiImage::clip(Params const & params)
#if QT_VERSION >= 0x050000
double const pixelRatio = is_transformed_ ? transformed_.devicePixelRatio() : original_.devicePixelRatio();
int const new_width = static_cast<int>((params.bb.xr - params.bb.xl) * pixelRatio);
int const new_height = static_cast<int>((params.bb.yt - params.bb.yb) * pixelRatio);
int const new_width = static_cast<int>((params.bb.xr.inBP() - params.bb.xl.inBP()) * pixelRatio);
int const new_height = static_cast<int>((params.bb.yt.inBP() - params.bb.yb.inBP()) * pixelRatio);
#else
int const new_width = static_cast<int>((params.bb.xr - params.bb.xl));
int const new_height = static_cast<int>((params.bb.yt - params.bb.yb));
int const new_width = static_cast<int>((params.bb.xr.inBP() - params.bb.xl.inBP()));
int const new_height = static_cast<int>((params.bb.yt.inBP() - params.bb.yb.inBP()));
#endif
QImage const & image = is_transformed_ ? transformed_ : original_;
@ -162,9 +162,9 @@ bool GuiImage::clip(Params const & params)
if (new_width == image.width() && new_height == image.height())
return false;
int const xoffset_l = params.bb.xl;
int const yoffset_t = (image.height() > int(params.bb.yt))
? image.height() - params.bb.yt : 0;
int const xoffset_l = params.bb.xl.inBP();
int const yoffset_t = (image.height() > params.bb.yt.inBP())
? image.height() - params.bb.yt.inBP() : 0;
transformed_ = image.copy(xoffset_l, yoffset_t, new_width, new_height);
return true;

View File

@ -518,7 +518,7 @@
</property>
</widget>
</item>
<item row="3" column="1" colspan="2" >
<item row="3" column="1" >
<widget class="QLineEdit" name="xlED" >
<property name="toolTip" >
<string/>
@ -548,9 +548,21 @@
</property>
</widget>
</item>
<item row="2" column="1" colspan="2" >
<item row="2" column="1" >
<widget class="QLineEdit" name="xrED" />
</item>
<item row="2" column="2" >
<widget class="lyx::frontend::LengthCombo" name="xrUnitCO" />
</item>
<item row="2" column="4" >
<widget class="lyx::frontend::LengthCombo" name="ytUnitCO" />
</item>
<item row="3" column="2" >
<widget class="lyx::frontend::LengthCombo" name="xlUnitCO" />
</item>
<item row="3" column="4" >
<widget class="lyx::frontend::LengthCombo" name="ybUnitCO" />
</item>
</layout>
</widget>
</item>

View File

@ -12,8 +12,6 @@
#include "GraphicsParams.h"
#include "Length.h"
#include <cstdlib>
#include <sstream>
@ -49,18 +47,17 @@ bool operator!=(Params const & a, Params const & b)
ostream & operator<<(ostream & os, BoundingBox const & bb)
{
os << bb.xl << ' ' << bb.yb << ' ' << bb.xr << ' ' << bb.yt;
os << bb.xl.asString() << ' ' << bb.yb.asString() << ' '
<< bb.xr.asString() << ' ' << bb.yt.asString();
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;
@ -69,14 +66,22 @@ BoundingBox::BoundingBox(string const & bb)
string a, b, c, d;
is >> a >> b >> c >> d;
Length xl_tmp = Length(a);
if (xl_tmp.value() < 0)
xl_tmp = Length(-xl_tmp.value(), xl_tmp.unit());
Length yb_tmp = Length(b);
if (yb_tmp.value() < 0)
yb_tmp = Length(-yb_tmp.value(), yb_tmp.unit());
Length xr_tmp = Length(c);
if (xr_tmp.value() < 0)
xr_tmp = Length(-xr_tmp.value(), xr_tmp.unit());
Length yt_tmp = Length(d);
if (yt_tmp.value() < 0)
yt_tmp = Length(-yt_tmp.value(), yt_tmp.unit());
// inBP returns the length in Postscript points.
// Note further that there are 72 Postscript pixels per inch.
unsigned int const xl_tmp = abs(Length(a).inBP());
unsigned int const yb_tmp = abs(Length(b).inBP());
unsigned int const xr_tmp = abs(Length(c).inBP());
unsigned int const yt_tmp = abs(Length(d).inBP());
if (xr_tmp <= xl_tmp || yt_tmp <= yb_tmp)
if (xr_tmp.inBP() <= xl_tmp.inBP() || yt_tmp.inBP() <= yb_tmp.inBP())
return;
xl = xl_tmp;
@ -88,7 +93,7 @@ BoundingBox::BoundingBox(string const & bb)
bool BoundingBox::empty() const
{
return (!xl && !yb && !xr && !yt);
return xl.zero() && yb.zero() && xr.zero() && yt.zero();
}

View File

@ -14,6 +14,8 @@
#ifndef GRAPHICSPARAMS_H
#define GRAPHICSPARAMS_H
#include "Length.h"
#include "support/FileName.h"
#include <string>
@ -36,15 +38,16 @@ public:
/// 0 0 0 0 is empty!
bool empty() const;
unsigned int xl;
unsigned int yb;
unsigned int xr;
unsigned int yt;
Length xl;
Length yb;
Length xr;
Length yt;
};
bool operator==(BoundingBox const &, BoundingBox const &);
bool operator!=(BoundingBox const &, BoundingBox const &);
/// output bounding box in LyX file format
std::ostream & operator<<(std::ostream &, BoundingBox const &);

View File

@ -218,7 +218,10 @@ string const ClipLatexOption::option_impl() const
ostringstream os;
if (!data.bbox.empty())
os << "bb=" << data.bbox << ',';
os << "bb=" << data.bbox.xl.asLatexString() << ' '
<< data.bbox.yb.asLatexString() << ' '
<< data.bbox.xr.asLatexString() << ' '
<< data.bbox.yt.asLatexString() << ',';
if (data.clip)
os << "clip,";
return os.str();

View File

@ -36,7 +36,9 @@ class ClipData {
public:
ClipData() : clip(false) {}
/// The bounding box
graphics::BoundingBox bbox;
/// clip image
bool clip;
};

View File

@ -293,13 +293,13 @@ bool InsetExternalParams::read(Buffer const & buffer, Lexer & lex)
case EX_BOUNDINGBOX:
lex.next();
clipdata.bbox.xl = lex.getInteger();
clipdata.bbox.xl = Length(lex.getString());
lex.next();
clipdata.bbox.yb = lex.getInteger();
clipdata.bbox.yb = Length(lex.getString());
lex.next();
clipdata.bbox.xr = lex.getInteger();
clipdata.bbox.xr = Length(lex.getString());
lex.next();
clipdata.bbox.yt = lex.getInteger();
clipdata.bbox.yt = Length(lex.getString());
break;
case EX_CLIP:

View File

@ -262,36 +262,36 @@ graphics::Params InsetGraphicsParams::as_grfxParams() const
unsigned int const bb_orig_yb = convert<unsigned int>(token(tmp, ' ', 1));
// new pars.bb values must be >= zero
if (pars.bb.xl > bb_orig_xl)
pars.bb.xl -= bb_orig_xl;
if (pars.bb.xl.inBP() > static_cast<int>(bb_orig_xl))
pars.bb.xl = Length(pars.bb.xl.inBP() - bb_orig_xl, Length::BP);
else
pars.bb.xl = 0;
pars.bb.xl = Length();
if (pars.bb.xr > bb_orig_xl)
pars.bb.xr -= bb_orig_xl;
if (pars.bb.xr.inBP() > static_cast<int>(bb_orig_xl))
pars.bb.xr = Length(pars.bb.xr.inBP() - bb_orig_xl, Length::BP);
else
pars.bb.xr = 0;
pars.bb.xr = Length();
if (pars.bb.yb > bb_orig_yb)
pars.bb.yb -= bb_orig_yb;
if (pars.bb.yb.inBP() > static_cast<int>(bb_orig_yb))
pars.bb.yb = Length(pars.bb.yb.inBP() - bb_orig_yb, Length::BP);
else
pars.bb.yb = 0;
pars.bb.yb = Length();
if (pars.bb.yt > bb_orig_yb)
pars.bb.yt -= bb_orig_yb;
if (pars.bb.yt.inBP() > static_cast<int>(bb_orig_yb))
pars.bb.yt = Length(pars.bb.yt.inBP() - bb_orig_yb, Length::BP);
else
pars.bb.yt = 0;
pars.bb.yt = Length();
}
// Paranoia check.
int const width = pars.bb.xr - pars.bb.xl;
int const height = pars.bb.yt - pars.bb.yb;
int const width = pars.bb.xr.inBP() - pars.bb.xl.inBP();
int const height = pars.bb.yt.inBP() - pars.bb.yb.inBP();
if (width < 0 || height < 0) {
pars.bb.xl = 0;
pars.bb.xr = 0;
pars.bb.yb = 0;
pars.bb.yt = 0;
pars.bb.xl = Length();
pars.bb.xr = Length();
pars.bb.yb = Length();
pars.bb.yt = Length();
}
}

View File

@ -1,5 +1,5 @@
#LyX file created by tex2lyx 2.2
\lyxformat 496
\lyxformat 497
\begin_document
\begin_header
\origin roundtrip

View File

@ -1,5 +1,5 @@
#LyX file created by tex2lyx 2.2
\lyxformat 496
\lyxformat 497
\begin_document
\begin_header
\origin roundtrip

View File

@ -1,5 +1,5 @@
#LyX file created by tex2lyx 2.2
\lyxformat 496
\lyxformat 497
\begin_document
\begin_header
\origin roundtrip

View File

@ -1,5 +1,5 @@
#LyX file created by tex2lyx 2.2
\lyxformat 496
\lyxformat 497
\begin_document
\begin_header
\origin roundtrip

View File

@ -1,5 +1,5 @@
#LyX file created by tex2lyx 2.2
\lyxformat 496
\lyxformat 497
\begin_document
\begin_header
\origin roundtrip

View File

@ -1,5 +1,5 @@
#LyX file created by tex2lyx 2.2
\lyxformat 496
\lyxformat 497
\begin_document
\begin_header
\origin roundtrip

View File

@ -1,5 +1,5 @@
#LyX file created by tex2lyx 2.2
\lyxformat 496
\lyxformat 497
\begin_document
\begin_header
\origin roundtrip

View File

@ -1,5 +1,5 @@
#LyX file created by tex2lyx 2.2
\lyxformat 496
\lyxformat 497
\begin_document
\begin_header
\origin roundtrip

View File

@ -1,5 +1,5 @@
#LyX file created by tex2lyx 2.2
\lyxformat 496
\lyxformat 497
\begin_document
\begin_header
\origin roundtrip

View File

@ -1,5 +1,5 @@
#LyX file created by tex2lyx 2.2
\lyxformat 496
\lyxformat 497
\begin_document
\begin_header
\origin roundtrip

View File

@ -1,5 +1,5 @@
#LyX file created by tex2lyx 2.2
\lyxformat 496
\lyxformat 497
\begin_document
\begin_header
\origin roundtrip

View File

@ -1,5 +1,5 @@
#LyX file created by tex2lyx 2.2
\lyxformat 496
\lyxformat 497
\begin_document
\begin_header
\origin roundtrip

View File

@ -1,5 +1,5 @@
#LyX file created by tex2lyx 2.2
\lyxformat 496
\lyxformat 497
\begin_document
\begin_header
\origin roundtrip

View File

@ -1,5 +1,5 @@
#LyX file created by tex2lyx 2.2
\lyxformat 496
\lyxformat 497
\begin_document
\begin_header
\origin roundtrip

View File

@ -1,5 +1,5 @@
#LyX file created by tex2lyx 2.2
\lyxformat 496
\lyxformat 497
\begin_document
\begin_header
\origin roundtrip

View File

@ -1,5 +1,5 @@
#LyX file created by tex2lyx 2.2
\lyxformat 496
\lyxformat 497
\begin_document
\begin_header
\origin roundtrip

View File

@ -32,8 +32,8 @@ extern char const * const lyx_version_info;
// Do not remove the comment below, so we get merge conflict in
// independent branches. Instead add your own.
#define LYX_FORMAT_LYX 496 // gb: remove noUnzip parameter of InsetGraphics
#define LYX_FORMAT_TEX2LYX 496
#define LYX_FORMAT_LYX 497 // gb: bounding box of external insets supports units
#define LYX_FORMAT_TEX2LYX 497
#if LYX_FORMAT_TEX2LYX != LYX_FORMAT_LYX
#ifndef _MSC_VER