Commit 8ac99b71 authored by twanvl's avatar twanvl

Rotation can now zoom in x and y directions separatly; text can be scaled...

Rotation can now zoom in x and y directions separatly; text can be scaled stretched/compressed horizontally.
parent 8329d144
...@@ -56,6 +56,16 @@ TextStyle::TextStyle(const TextFieldP& field) ...@@ -56,6 +56,16 @@ TextStyle::TextStyle(const TextFieldP& field)
, direction(LEFT_TO_RIGHT) , direction(LEFT_TO_RIGHT)
{} {}
double TextStyle::getStretch() const {
if (content_width > 0 && ((alignment() & ALIGN_STRETCH) || (alignment() & ALIGN_STRETCH_OVERFLOW))) {
double factor = (width - padding_left - padding_right) / content_width;
if (alignment() == ALIGN_STRETCH || factor < 1.0) {
return factor;
}
}
return 1.0;
}
bool TextStyle::update(Context& ctx) { bool TextStyle::update(Context& ctx) {
return Style ::update(ctx) return Style ::update(ctx)
| font .update(ctx) | font .update(ctx)
......
...@@ -80,8 +80,14 @@ class TextStyle : public Style { ...@@ -80,8 +80,14 @@ class TextStyle : public Style {
/// The rotation to use when drawing /// The rotation to use when drawing
inline Rotation getRotation() const { inline Rotation getRotation() const {
return Rotation(angle, getRect(), 1.0, getStretch());
}
/// The rotation to use when determining content layout, does not include the stretch factor
inline Rotation getRotationNoStretch() const {
return Rotation(angle, getRect()); return Rotation(angle, getRect());
} }
/// Stretch factor to use
double getStretch() const;
private: private:
DECLARE_REFLECTION(); DECLARE_REFLECTION();
......
...@@ -45,10 +45,11 @@ void sharp_resample_and_clip(const Image& img_in, Image& img_out, wxRect rect, i ...@@ -45,10 +45,11 @@ void sharp_resample_and_clip(const Image& img_in, Image& img_out, wxRect rect, i
/// Draw text by first drawing it using a larger font and then downsampling it /// Draw text by first drawing it using a larger font and then downsampling it
/** optionally rotated by an angle. /** optionally rotated by an angle.
* rect = rectangle to draw in * rect = rectangle to draw in
* (wc,hc) = the corner where drawing should begin, (0,0) for top-left, (1,1) for bottom-right * stretch_x = amount to stretch horizontally after drawing
* (wc,hc) = the corner where drawing should begin, (0,0) for top-left, (1,1) for bottom-right
*/ */
void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle, const String& text, int blur_radius = 0, int repeat = 1); void draw_resampled_text(DC& dc, const RealRect& rect, double stretch_x, int wc, int hc, int angle, const String& text, int blur_radius = 0, int repeat = 1);
// scaling factor to use when drawing resampled text // scaling factor to use when drawing resampled text
extern const int text_scaling; extern const int text_scaling;
......
...@@ -20,27 +20,62 @@ const int text_scaling = 4; ...@@ -20,27 +20,62 @@ const int text_scaling = 4;
// Downsamples the red channel of the input image to the alpha channel of the output image // Downsamples the red channel of the input image to the alpha channel of the output image
// img_in must be text_scaling times as large as img_out // img_in must be text_scaling times as large as img_out
void downsample_to_alpha(Image& img_in, Image& img_out) { void downsample_to_alpha(Image& img_in, Image& img_out) {
assert(img_in.GetWidth() == img_out.GetWidth() * text_scaling);
assert(img_in.GetHeight() == img_out.GetHeight() * text_scaling); assert(img_in.GetHeight() == img_out.GetHeight() * text_scaling);
// scale in the x direction, this overwrites parts of the input image Byte* temp = nullptr;
Byte* in = img_in.GetData(); Byte* in = img_in.GetData();
Byte* out = img_in.GetData(); Byte* out = img_in.GetData();
int count = img_out.GetWidth() * img_in.GetHeight(); // scale in the x direction, this overwrites parts of the input image
for (int i = 0 ; i < count ; ++i) { if (img_in.GetWidth() == img_out.GetWidth() * text_scaling) {
int total = 0; // no stretching
for (int j = 0 ; j < text_scaling ; ++j) { int count = img_out.GetWidth() * img_in.GetHeight();
total += in[3 * (j + text_scaling * i)]; for (int i = 0 ; i < count ; ++i) {
int total = 0;
for (int j = 0 ; j < text_scaling ; ++j) {
total += in[3 * (j + text_scaling * i)];
}
out[i] = total / text_scaling;
} }
out[i] = total / text_scaling; } else {
// resample to buffer
temp = new Byte[img_out.GetWidth() * img_in.GetHeight()];
out = temp;
// custom stretch, see resample_image.cpp
const int shift = 32-12-8; // => max size = 4096, max alpha = 255
int w1 = img_in.GetWidth(), w2 = img_out.GetWidth(), h = img_in.GetHeight();
int out_fact = (w2 << shift) / w1; // how much to output for 256 input = 1 pixel
int out_rest = (w2 << shift) % w1;
for (int y = 0 ; y < h ; ++y) {
int in_rem = out_fact + out_rest;
for (int x = 0 ; x < w2 ; ++x) {
int out_rem = 1 << shift;
int tot = 0;
while (out_rem >= in_rem) {
// eat a whole input pixel
tot += *in * in_rem;
out_rem -= in_rem;
in_rem = out_fact;
in += 3;
}
if (out_rem > 0) {
// eat a partial input pixel
tot += *in * out_rem;
in_rem -= out_rem;
}
// store
*out = tot >> shift;
out += 1;
}
}
in = temp;
} }
// now scale in the y direction, and write to the output alpha // now scale in the y direction, and write to the output alpha
img_out.InitAlpha(); img_out.InitAlpha();
out = img_out.GetAlpha(); out = img_out.GetAlpha();
int line_size = img_out.GetWidth(); int line_size = img_out.GetWidth();
for (int y = 0 ; y < img_out.GetHeight() ; ++y) { for (int y = 0 ; y < img_out.GetHeight() ; ++y) {
for (int x = 0 ; x < img_out.GetWidth() ; ++x) { for (int x = 0 ; x < line_size ; ++x) {
int total = 0; int total = 0;
for (int j = 0 ; j < text_scaling ; ++j) { for (int j = 0 ; j < text_scaling ; ++j) {
total += in[x + line_size * (j + text_scaling * y)]; total += in[x + line_size * (j + text_scaling * y)];
...@@ -49,26 +84,7 @@ void downsample_to_alpha(Image& img_in, Image& img_out) { ...@@ -49,26 +84,7 @@ void downsample_to_alpha(Image& img_in, Image& img_out) {
} }
} }
/* delete[] temp;
img_out.InitAlpha();
Byte* in = img_in.GetData();
Byte* out = img_out.GetAlpha();
int w = img_out.GetWidth(), h = img_out.GetHeight();
int line_size = 3 * w * text_scaling;
for (int y = 0 ; y < h ; ++y) {
for (int x = 0 ; x < w ; ++x) {
int total = 0;
for (int i = 0 ; i < text_scaling ; ++i) {
for (int j = 0 ; j < text_scaling ; ++j) {
total += in[3*j];
}
in += line_size;
}
*out++ = total / (text_scaling * text_scaling);
in += 3 * text_scaling - line_size * text_scaling;
}
in += line_size * (text_scaling - 1);
}*/
} }
// simple blur // simple blur
...@@ -97,7 +113,7 @@ void blur_image_alpha(Image& img) { ...@@ -97,7 +113,7 @@ void blur_image_alpha(Image& img) {
// optionally rotated by an angle // optionally rotated by an angle
// (w2,h2) = size of text // (w2,h2) = size of text
// (wc,hc) = the corner where drawing should begin, (0,0) for top-left, (1,1) for bottom-right // (wc,hc) = the corner where drawing should begin, (0,0) for top-left, (1,1) for bottom-right
void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle, const String& text, int blur_radius, int repeat) { void draw_resampled_text(DC& dc, const RealRect& rect, double stretch_x, int wc, int hc, int angle, const String& text, int blur_radius, int repeat) {
// enlarge slightly; some fonts are larger then the GetTextExtent tells us (especially italic fonts) // enlarge slightly; some fonts are larger then the GetTextExtent tells us (especially italic fonts)
int w = static_cast<int>(rect.width) + 3 + 2 * blur_radius, h = static_cast<int>(rect.height) + 1 + 2 * blur_radius; int w = static_cast<int>(rect.width) + 3 + 2 * blur_radius, h = static_cast<int>(rect.height) + 1 + 2 * blur_radius;
// determine sub-pixel position // determine sub-pixel position
...@@ -116,7 +132,7 @@ void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle ...@@ -116,7 +132,7 @@ void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle
mdc.SelectObject(wxNullBitmap); mdc.SelectObject(wxNullBitmap);
Image img_large = buffer.ConvertToImage(); Image img_large = buffer.ConvertToImage();
// step 2. sample down // step 2. sample down
Image img_small(w, h, false); Image img_small(stretch_x * w, h, false);
fill_image(img_small, dc.GetTextForeground()); fill_image(img_small, dc.GetTextForeground());
downsample_to_alpha(img_large, img_small); downsample_to_alpha(img_large, img_small);
// blur // blur
......
...@@ -776,10 +776,10 @@ void TextValueEditor::determineSize(bool force_fit) { ...@@ -776,10 +776,10 @@ void TextValueEditor::determineSize(bool force_fit) {
int sbw = wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); int sbw = wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
RealPoint pos = rot.tr(style().getPos()); RealPoint pos = rot.tr(style().getPos());
scrollbar->SetSize( scrollbar->SetSize(
(int)(pos.x + rot.trS(style().width) + 1 - sbw), (int)(pos.x + rot.trX(style().width) + 1 - sbw),
(int)pos.y - 1, (int)pos.y - 1,
(int)sbw, (int)sbw,
(int)rot.trS(style().height) + 2); (int)rot.trY(style().height) + 2);
v.reset(); v.reset();
} else { } else {
// Height depends on font // Height depends on font
......
...@@ -134,7 +134,7 @@ void TextViewer::drawSeparators(RotatedDC& dc) { ...@@ -134,7 +134,7 @@ void TextViewer::drawSeparators(RotatedDC& dc) {
bool TextViewer::prepare(RotatedDC& dc, const String& text, TextStyle& style, Context& ctx) { bool TextViewer::prepare(RotatedDC& dc, const String& text, TextStyle& style, Context& ctx) {
if (lines.empty()) { if (lines.empty()) {
// not prepared yet // not prepared yet
Rotater r(dc, style.getRotation()); Rotater r(dc, style.getRotationNoStretch());
prepareElements(text, style, ctx); prepareElements(text, style, ctx);
prepareLines(dc, text, style, ctx); prepareLines(dc, text, style, ctx);
return true; return true;
......
...@@ -35,8 +35,8 @@ void ChoiceValueViewer::draw(RotatedDC& dc) { ...@@ -35,8 +35,8 @@ void ChoiceValueViewer::draw(RotatedDC& dc) {
} else if(style().render_style & RENDER_TEXT) { } else if(style().render_style & RENDER_TEXT) {
// also drawing text, use original size // also drawing text, use original size
} else { } else {
img_options.width = (int) dc.trS(style().width); img_options.width = (int) dc.trX(style().width);
img_options.height = (int) dc.trS(style().height); img_options.height = (int) dc.trY(style().height);
img_options.preserve_aspect = style().alignment == ALIGN_STRETCH ? ASPECT_STRETCH : ASPECT_FIT; img_options.preserve_aspect = style().alignment == ALIGN_STRETCH ? ASPECT_STRETCH : ASPECT_FIT;
} }
Image image = img.generate(img_options, true); Image image = img.generate(img_options, true);
......
...@@ -93,7 +93,7 @@ void ColorValueViewer::onStyleChange(bool already_prepared) { ...@@ -93,7 +93,7 @@ void ColorValueViewer::onStyleChange(bool already_prepared) {
void ColorValueViewer::loadMask(const Rotation& rot) const { void ColorValueViewer::loadMask(const Rotation& rot) const {
if (style().mask_filename().empty()) return; // no mask if (style().mask_filename().empty()) return; // no mask
int w = (int) rot.trS(style().width), h = (int) rot.trS(style().height); int w = (int) rot.trX(style().width), h = (int) rot.trY(style().height);
if (alpha_mask && alpha_mask->size == wxSize(w,h)) return; // mask loaded and right size if (alpha_mask && alpha_mask->size == wxSize(w,h)) return; // mask loaded and right size
// (re) load the mask // (re) load the mask
Image image; Image image;
......
...@@ -22,7 +22,7 @@ void ImageValueViewer::draw(RotatedDC& dc) { ...@@ -22,7 +22,7 @@ void ImageValueViewer::draw(RotatedDC& dc) {
InputStreamP image_file = getSet().openIn(value().filename); InputStreamP image_file = getSet().openIn(value().filename);
Image image; Image image;
if (image.LoadFile(*image_file)) { if (image.LoadFile(*image_file)) {
image.Rescale((int)dc.trS(style().width), (int)dc.trS(style().height)); image.Rescale((int)dc.trX(style().width), (int)dc.trY(style().height));
// apply mask to image // apply mask to image
loadMask(dc); loadMask(dc);
if (alpha_mask) alpha_mask->setAlpha(image); if (alpha_mask) alpha_mask->setAlpha(image);
...@@ -34,7 +34,7 @@ void ImageValueViewer::draw(RotatedDC& dc) { ...@@ -34,7 +34,7 @@ void ImageValueViewer::draw(RotatedDC& dc) {
} }
// if there is no image, generate a placeholder // if there is no image, generate a placeholder
if (!bitmap.Ok()) { if (!bitmap.Ok()) {
UInt w = (UInt)dc.trS(style().width), h = (UInt)dc.trS(style().height); UInt w = (UInt)dc.trX(style().width), h = (UInt)dc.trY(style().height);
loadMask(dc); loadMask(dc);
if (style().default_image.isReady()) { if (style().default_image.isReady()) {
// we have a script to use for the default image // we have a script to use for the default image
...@@ -85,7 +85,7 @@ void ImageValueViewer::onStyleChange(bool already_prepared) { ...@@ -85,7 +85,7 @@ void ImageValueViewer::onStyleChange(bool already_prepared) {
void ImageValueViewer::loadMask(const Rotation& rot) const { void ImageValueViewer::loadMask(const Rotation& rot) const {
if (style().mask_filename().empty()) return; // no mask if (style().mask_filename().empty()) return; // no mask
int w = (int) rot.trS(style().width), h = (int) rot.trS(style().height); int w = (int) rot.trX(style().width), h = (int) rot.trY(style().height);
if (alpha_mask && alpha_mask->size == wxSize(w,h)) return; // mask loaded and right size if (alpha_mask && alpha_mask->size == wxSize(w,h)) return; // mask loaded and right size
// (re) load the mask // (re) load the mask
Image image; Image image;
......
...@@ -56,8 +56,8 @@ void MultipleChoiceValueViewer::draw(RotatedDC& dc) { ...@@ -56,8 +56,8 @@ void MultipleChoiceValueViewer::draw(RotatedDC& dc) {
} else if(style().render_style & RENDER_TEXT) { } else if(style().render_style & RENDER_TEXT) {
// also drawing text, use original size // also drawing text, use original size
} else { } else {
img_options.width = (int) dc.trS(style().width); img_options.width = (int) dc.trX(style().width);
img_options.height = (int) dc.trS(style().height); img_options.height = (int) dc.trY(style().height);
img_options.preserve_aspect = style().alignment == ALIGN_STRETCH ? ASPECT_STRETCH : ASPECT_FIT; img_options.preserve_aspect = style().alignment == ALIGN_STRETCH ? ASPECT_STRETCH : ASPECT_FIT;
} }
Image image = img.generate(img_options, true); Image image = img.generate(img_options, true);
......
...@@ -36,16 +36,18 @@ RealPoint align_in_rect(Alignment align, const RealSize& to_align, const RealRec ...@@ -36,16 +36,18 @@ RealPoint align_in_rect(Alignment align, const RealSize& to_align, const RealRec
/// Convert a String to an Alignment /// Convert a String to an Alignment
Alignment from_string(const String& s) { Alignment from_string(const String& s) {
int al = ALIGN_TOP_LEFT; int al = ALIGN_TOP_LEFT;
if (s.find(_("left")) !=String::npos) al = ALIGN_LEFT | (al & ~ALIGN_HORIZONTAL); if (s.find(_("left")) !=String::npos) al = ALIGN_LEFT | (al & ~ALIGN_HORIZONTAL);
if (s.find(_("center")) !=String::npos) al = ALIGN_CENTER | (al & ~ALIGN_HORIZONTAL); if (s.find(_("center")) !=String::npos) al = ALIGN_CENTER | (al & ~ALIGN_HORIZONTAL);
if (s.find(_("right")) !=String::npos) al = ALIGN_RIGHT | (al & ~ALIGN_HORIZONTAL); if (s.find(_("right")) !=String::npos) al = ALIGN_RIGHT | (al & ~ALIGN_HORIZONTAL);
if (s.find(_("justify")) !=String::npos) al = ALIGN_JUSTIFY | (al & ~ALIGN_HORIZONTAL); if (s.find(_("justify")) !=String::npos) al = ALIGN_JUSTIFY | (al & ~ALIGN_HORIZONTAL);
if (s.find(_("justify-words")) !=String::npos) al = ALIGN_JUSTIFY_WORDS | (al & ~ALIGN_HORIZONTAL); if (s.find(_("justify-words")) !=String::npos) al = ALIGN_JUSTIFY_WORDS | (al & ~ALIGN_HORIZONTAL);
if (s.find(_("shrink-overflow"))!=String::npos) al = ALIGN_JUSTIFY_OVERFLOW | (al & ~ALIGN_JUSTIFY_OVERFLOW); if (s.find(_("justify-overflow")) !=String::npos) al = ALIGN_JUSTIFY_OVERFLOW | (al & ~ALIGN_JUSTIFY_OVERFLOW);
if (s.find(_("top")) !=String::npos) al = ALIGN_TOP | (al & ~ALIGN_VERTICAL); if (s.find(_("shrink-overflow")) !=String::npos) al = ALIGN_STRETCH_OVERFLOW | (al & ~ALIGN_STRETCH_OVERFLOW); // compatability
if (s.find(_("middle")) !=String::npos) al = ALIGN_MIDDLE | (al & ~ALIGN_VERTICAL); if (s.find(_("stretch-overflow")) !=String::npos) al = ALIGN_STRETCH_OVERFLOW | (al & ~ALIGN_STRETCH_OVERFLOW);
if (s.find(_("bottom")) !=String::npos) al = ALIGN_BOTTOM | (al & ~ALIGN_VERTICAL); if (s.find(_("top")) !=String::npos) al = ALIGN_TOP | (al & ~ALIGN_VERTICAL);
if (s.find(_("stretch")) !=String::npos) al = ALIGN_STRETCH; if (s.find(_("middle")) !=String::npos) al = ALIGN_MIDDLE | (al & ~ALIGN_VERTICAL);
if (s.find(_("bottom")) !=String::npos) al = ALIGN_BOTTOM | (al & ~ALIGN_VERTICAL);
if (s.find(_("stretch")) !=String::npos) al = ALIGN_STRETCH;
return static_cast<Alignment>(al); return static_cast<Alignment>(al);
} }
...@@ -62,8 +64,9 @@ String to_string(Alignment align) { ...@@ -62,8 +64,9 @@ String to_string(Alignment align) {
if (align & ALIGN_LEFT) ret += _(" right"); if (align & ALIGN_LEFT) ret += _(" right");
if (align & ALIGN_LEFT) ret += _(" justify"); if (align & ALIGN_LEFT) ret += _(" justify");
if (align & ALIGN_LEFT) ret += _(" justify-words"); if (align & ALIGN_LEFT) ret += _(" justify-words");
if (align & ALIGN_JUSTIFY_OVERFLOW) ret += _(" justify-overflow");
// modifier // modifier
if (align & ALIGN_JUSTIFY_OVERFLOW) ret += _(" shrink-overflow"); if (align & ALIGN_STRETCH_OVERFLOW) ret += _(" stretch-overflow");
if (align & ALIGN_STRETCH) ret += _(" stretch"); if (align & ALIGN_STRETCH) ret += _(" stretch");
return ret.substr(1); return ret.substr(1);
} }
......
...@@ -30,7 +30,8 @@ enum Alignment ...@@ -30,7 +30,8 @@ enum Alignment
, ALIGN_VERTICAL = ALIGN_TOP | ALIGN_MIDDLE | ALIGN_BOTTOM , ALIGN_VERTICAL = ALIGN_TOP | ALIGN_MIDDLE | ALIGN_BOTTOM
// modifiers // modifiers
, ALIGN_JUSTIFY_OVERFLOW = 0x1000 , ALIGN_JUSTIFY_OVERFLOW = 0x1000
, ALIGN_STRETCH = 0x2000 , ALIGN_STRETCH_OVERFLOW = 0x2000
, ALIGN_STRETCH = 0x4000
// common combinations // common combinations
, ALIGN_TOP_LEFT = ALIGN_TOP | ALIGN_LEFT , ALIGN_TOP_LEFT = ALIGN_TOP | ALIGN_LEFT
, ALIGN_TOP_CENTER = ALIGN_TOP | ALIGN_CENTER , ALIGN_TOP_CENTER = ALIGN_TOP | ALIGN_CENTER
......
...@@ -18,11 +18,12 @@ int constrain_angle(int angle) { ...@@ -18,11 +18,12 @@ int constrain_angle(int angle) {
return (a / 90) * 90; // multiple of 90 return (a / 90) * 90; // multiple of 90
} }
Rotation::Rotation(int angle, const RealRect& rect, double zoom, bool is_internal) Rotation::Rotation(int angle, const RealRect& rect, double zoom, double strectch, bool is_internal)
: angle(constrain_angle(angle)) : angle(constrain_angle(angle))
, size(rect.size()) , size(rect.size())
, origin(rect.position()) , origin(rect.position())
, zoom(zoom) , zoomX(zoom * strectch)
, zoomY(zoom)
{ {
if (is_internal) { if (is_internal) {
size = trNoNeg(size); size = trNoNeg(size);
...@@ -41,9 +42,9 @@ RealPoint Rotation::tr(const RealPoint& p) const { ...@@ -41,9 +42,9 @@ RealPoint Rotation::tr(const RealPoint& p) const {
} }
RealSize Rotation::tr(const RealSize& s) const { RealSize Rotation::tr(const RealSize& s) const {
if (sideways()) { if (sideways()) {
return RealSize(negX(s.height), negY(s.width)) * zoom; return RealSize(negX(s.height) * zoomY, negY(s.width) * zoomX);
} else { } else {
return RealSize(negX(s.width), negY(s.height)) * zoom; return RealSize(negX(s.width) * zoomX, negY(s.height) * zoomY);
} }
} }
RealRect Rotation::tr(const RealRect& r) const { RealRect Rotation::tr(const RealRect& r) const {
...@@ -52,13 +53,13 @@ RealRect Rotation::tr(const RealRect& r) const { ...@@ -52,13 +53,13 @@ RealRect Rotation::tr(const RealRect& r) const {
RealSize Rotation::trNoNeg(const RealSize& s) const { RealSize Rotation::trNoNeg(const RealSize& s) const {
if (sideways()) { if (sideways()) {
return RealSize(s.height, s.width) * zoom; return RealSize(s.height * zoomY, s.width * zoomX);
} else { } else {
return RealSize(s.width, s.height) * zoom; return RealSize(s.width * zoomX, s.height * zoomY);
} }
} }
RealRect Rotation::trNoNeg(const RealRect& r) const { RealRect Rotation::trNoNeg(const RealRect& r) const {
RealSize s = (sideways() ? RealSize(r.height, r.width) : r.size()) * zoom; RealSize s = trNoNeg(r.size());
return RealRect(tr(r.position()) - RealSize(revX()?s.width:0, revY()?s.height:0), s); return RealRect(tr(r.position()) - RealSize(revX()?s.width:0, revY()?s.height:0), s);
} }
RealRect Rotation::trNoNegNoZoom(const RealRect& r) const { RealRect Rotation::trNoNegNoZoom(const RealRect& r) const {
...@@ -69,14 +70,14 @@ RealRect Rotation::trNoNegNoZoom(const RealRect& r) const { ...@@ -69,14 +70,14 @@ RealRect Rotation::trNoNegNoZoom(const RealRect& r) const {
RealSize Rotation::trInv(const RealSize& s) const { RealSize Rotation::trInv(const RealSize& s) const {
if (sideways()) { if (sideways()) {
return RealSize(negY(s.height), negX(s.width)) / zoom; return RealSize(negY(s.height) / zoomY, negX(s.width) / zoomX);
} else { } else {
return RealSize(negX(s.width), negY(s.height)) / zoom; return RealSize(negX(s.width) / zoomX, negY(s.height) / zoomY);
} }
} }
RealPoint Rotation::trInv(const RealPoint& p) const { RealPoint Rotation::trInv(const RealPoint& p) const {
RealPoint p2 = (p - origin) / zoom; RealPoint p2((p.x - origin.x) / zoomX, (p.y - origin.y) / zoomY);
if (sideways()) { if (sideways()) {
return RealPoint(negY(p2.y), negX(p2.x)); return RealPoint(negY(p2.y), negX(p2.x));
} else { } else {
...@@ -86,9 +87,9 @@ RealPoint Rotation::trInv(const RealPoint& p) const { ...@@ -86,9 +87,9 @@ RealPoint Rotation::trInv(const RealPoint& p) const {
RealSize Rotation::trInvNoNeg(const RealSize& s) const { RealSize Rotation::trInvNoNeg(const RealSize& s) const {
if (sideways()) { if (sideways()) {
return RealSize(s.height, s.width) / zoom; return RealSize(s.height / zoomY, s.width / zoomX);
} else { } else {
return RealSize(s.width, s.height) / zoom; return RealSize(s.width / zoomX, s.height / zoomY);
} }
} }
...@@ -101,7 +102,13 @@ Rotater::Rotater(Rotation& rot, const Rotation& by) ...@@ -101,7 +102,13 @@ Rotater::Rotater(Rotation& rot, const Rotation& by)
// apply rotation // apply rotation
RealRect new_ext = rot.trNoNeg(by.getExternalRect()); RealRect new_ext = rot.trNoNeg(by.getExternalRect());
rot.angle = constrain_angle(rot.angle + by.angle); rot.angle = constrain_angle(rot.angle + by.angle);
rot.zoom *= by.zoom; if (by.sideways()) {
rot.zoomX *= by.zoomY;
rot.zoomY *= by.zoomX;
} else {
rot.zoomX *= by.zoomX;
rot.zoomY *= by.zoomY;
}
rot.size = new_ext.size(); rot.size = new_ext.size();
rot.origin = new_ext.position() + RealSize(rot.revX() ? rot.size.width : 0, rot.revY() ? rot.size.height : 0); rot.origin = new_ext.position() + RealSize(rot.revX() ? rot.size.width : 0, rot.revY() ? rot.size.height : 0);
} }
...@@ -129,7 +136,7 @@ void RotatedDC::DrawText (const String& text, const RealPoint& pos, int blur_ra ...@@ -129,7 +136,7 @@ void RotatedDC::DrawText (const String& text, const RealPoint& pos, int blur_ra
if (quality == QUALITY_AA) { if (quality == QUALITY_AA) {
RealRect r(pos, GetTextExtent(text)); RealRect r(pos, GetTextExtent(text));
RealRect r_ext = trNoNeg(r); RealRect r_ext = trNoNeg(r);
draw_resampled_text(dc, r_ext, revX(), revY(), angle, text, blur_radius, boldness); draw_resampled_text(dc, r_ext, stretch(), revX(), revY(), angle, text, blur_radius, boldness);
} else if (quality == QUALITY_SUB_PIXEL) { } else if (quality == QUALITY_SUB_PIXEL) {
RealPoint p_ext = tr(pos)*text_scaling; RealPoint p_ext = tr(pos)*text_scaling;
double usx,usy; double usx,usy;
...@@ -210,14 +217,14 @@ void RotatedDC::SetTextForeground(const Color& color) { dc.SetTextForeground(col ...@@ -210,14 +217,14 @@ void RotatedDC::SetTextForeground(const Color& color) { dc.SetTextForeground(col
void RotatedDC::SetLogicalFunction(int function) { dc.SetLogicalFunction(function); } void RotatedDC::SetLogicalFunction(int function) { dc.SetLogicalFunction(function); }
void RotatedDC::SetFont(const wxFont& font) { void RotatedDC::SetFont(const wxFont& font) {
if (quality == QUALITY_LOW && zoom == 1) { if (quality == QUALITY_LOW && zoomX == 1 && zoomY == 1) {
dc.SetFont(font); dc.SetFont(font);
} else { } else {
wxFont scaled = font; wxFont scaled = font;
if (quality == QUALITY_LOW) { if (quality == QUALITY_LOW) {
scaled.SetPointSize((int) trS(font.GetPointSize())); scaled.SetPointSize((int) trY(font.GetPointSize()));
} else { } else {
scaled.SetPointSize((int) (trS(font.GetPointSize()) * text_scaling)); scaled.SetPointSize((int) (trY(font.GetPointSize()) * text_scaling));
} }
dc.SetFont(scaled); dc.SetFont(scaled);
} }
...@@ -244,9 +251,9 @@ RealSize RotatedDC::GetTextExtent(const String& text) const { ...@@ -244,9 +251,9 @@ RealSize RotatedDC::GetTextExtent(const String& text) const {
h += h - charHeight; h += h - charHeight;
#endif #endif
if (quality == QUALITY_LOW) { if (quality == QUALITY_LOW) {
return RealSize(w,h) / zoom; return RealSize(w / zoomX, h / zoomY);
} else { } else {
return RealSize(w,h) / zoom / text_scaling; return RealSize(w / (zoomX * text_scaling), h / (zoomY * text_scaling));
} }
} }
double RotatedDC::GetCharHeight() const { double RotatedDC::GetCharHeight() const {
...@@ -259,9 +266,9 @@ double RotatedDC::GetCharHeight() const { ...@@ -259,9 +266,9 @@ double RotatedDC::GetCharHeight() const {
h = 2 * extent - h; h = 2 * extent - h;
#endif #endif
if (quality == QUALITY_LOW) { if (quality == QUALITY_LOW) {
return h / zoom; return h / zoomY;
} else { } else {
return h / zoom / text_scaling; return h / (zoomY * text_scaling);
} }
} }
......
...@@ -28,10 +28,10 @@ class Rotation { ...@@ -28,10 +28,10 @@ class Rotation {
/** with the given rectangle of external coordinates and a given rotation angle and zoom factor. /** with the given rectangle of external coordinates and a given rotation angle and zoom factor.
* if is_internal then the rect gives the internal coordinates, its origin should be (0,0) * if is_internal then the rect gives the internal coordinates, its origin should be (0,0)
*/ */
Rotation(int angle, const RealRect& rect, double zoom = 1.0, bool is_internal = false); Rotation(int angle, const RealRect& rect, double zoom = 1.0, double strectch = 1.0, bool is_internal = false);
/// Change the zoom factor /// Change the zoom factor
inline void setZoom(double z) { zoom = z; } inline void setZoom(double z) { zoomX = zoomY = z; }
/// Change the angle /// Change the angle
void setAngle(int a); void setAngle(int a);
/// The internal size /// The internal size
...@@ -44,7 +44,9 @@ class Rotation { ...@@ -44,7 +44,9 @@ class Rotation {
RealRect getExternalRect() const; RealRect getExternalRect() const;
/// Translate a size or length /// Translate a size or length
inline double trS(double s) const { return s * zoom; } inline double trS(double s) const { return s * zoomY; }
inline double trX(double s) const { return s * zoomX; }
inline double trY(double s) const { return s * zoomY; }
/// Translate a single point /// Translate a single point
RealPoint tr(const RealPoint& p) const; RealPoint tr(const RealPoint& p) const;
...@@ -62,9 +64,11 @@ class Rotation { ...@@ -62,9 +64,11 @@ class Rotation {
RealRect trNoNegNoZoom(const RealRect& r) const; RealRect trNoNegNoZoom(const RealRect& r) const;
/// Translate a size or length back to internal 'coordinates' /// Translate a size or length back to internal 'coordinates'
inline double trInvS(double s) const { return s / zoom; } inline double trInvS(double s) const { return s / zoomY; }
inline double trInvX(double s) const { return s / zoomX; }
inline double trInvY(double s) const { return s / zoomY; }
/// Translate a size back to internal 'coordinates', doesn't rotate /// Translate a size back to internal 'coordinates', doesn't rotate
inline RealSize trInvS(const RealSize& s) const { return RealSize(s.width / zoom, s.height / zoom); } inline RealSize trInvS(const RealSize& s) const { return RealSize(s.width / zoomX, s.height / zoomY); }
/// Translate a point back to internal coordinates /// Translate a point back to internal coordinates
RealPoint trInv(const RealPoint& p) const; RealPoint trInv(const RealPoint& p) const;
...@@ -73,11 +77,15 @@ class Rotation { ...@@ -73,11 +77,15 @@ class Rotation {
/// Translate a size back to internal coordinates, that are not negative /// Translate a size back to internal coordinates, that are not negative
RealSize trInvNoNeg(const RealSize& s) const; RealSize trInvNoNeg(const RealSize& s) const;
/// Stretch factor
inline double stretch() const { return zoomX / zoomY; }
protected: protected:
int angle; ///< The angle of rotation in degrees (counterclockwise) int angle; ///< The angle of rotation in degrees (counterclockwise)
RealSize size; ///< Size of the rectangle, in external coordinates RealSize size; ///< Size of the rectangle, in external coordinates
RealPoint origin; ///< tr(0,0) RealPoint origin; ///< tr(0,0)
double zoom; ///< Zoom factor, zoom = 2.0 means that 1 internal = 2 external double zoomX; ///< Zoom factor, zoom = 2.0 means that 1 internal = 2 external
double zoomY;
friend class Rotater; friend class Rotater;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment