Commit 62a09e5b authored by twanvl's avatar twanvl

Support for masks for color fields

parent 94bdb630
......@@ -63,6 +63,12 @@ IMPLEMENT_REFLECTION(ColorStyle) {
REFLECT(right_width);
REFLECT(top_width);
REFLECT(bottom_width);
REFLECT_N("mask", mask_filename);
}
bool ColorStyle::update(Context& ctx) {
return Style ::update(ctx)
| mask_filename.update(ctx);
}
// ----------------------------------------------------------------------------- : ColorValue
......
......@@ -58,12 +58,15 @@ class ColorStyle : public Style {
ColorStyle(const ColorFieldP& field);
DECLARE_STYLE_TYPE(Color);
int radius; ///< Radius of round corners
UInt left_width; ///< Width of the colored region on the left side
UInt right_width; ///< Width of the colored region on the right side
UInt top_width; ///< Width of the colored region on the top side
UInt bottom_width; ///< Width of the colored region on the bottom side
double radius; ///< Radius of round corners
double left_width; ///< Width of the colored region on the left side
double right_width; ///< Width of the colored region on the right side
double top_width; ///< Width of the colored region on the top side
double bottom_width; ///< Width of the colored region on the bottom side
Scriptable<String> mask_filename; ///< Filename of an additional mask over the images
virtual bool update(Context&);
private:
DECLARE_REFLECTION();
};
......
......@@ -56,3 +56,16 @@ Color saturate(const Color& c, double amount) {
col(static_cast<int>( (b - amount * l) / (1 - amount) ))
);
}
void fill_image(Image& image, const Color& color) {
Byte* pos = image.GetData();
Byte* end = pos + image.GetWidth() * image.GetHeight() * 3;
Byte r = color.Red(), g = color.Green(), b = color.Blue();
// fill the image
while (pos != end) {
*pos++ = r;
*pos++ = g;
*pos++ = b;
}
}
......@@ -189,5 +189,8 @@ Color darken(const Color& c);
/// A saturated version of a color
Color saturate(const Color& c, double amount);
/// Fills an image with the specified color
void fill_image(Image& image, const Color& color);
// ----------------------------------------------------------------------------- : EOF
#endif
......@@ -15,19 +15,6 @@
// scaling factor to use when drawing resampled text
const int text_scaling = 4;
// Fills an image with the specified color
void fill_image(Image& image, const Color& color) {
Byte* pos = image.GetData();
Byte* end = pos + image.GetWidth() * image.GetHeight() * 3;
Byte r = color.Red(), g = color.Green(), b = color.Blue();
// fill the image
while (pos != end) {
*pos++ = r;
*pos++ = g;
*pos++ = b;
}
}
// 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
void downsample_to_alpha(Image& img_in, Image& img_out) {
......
......@@ -7,6 +7,8 @@
// ----------------------------------------------------------------------------- : Includes
#include <render/value/color.hpp>
#include <render/card/viewer.hpp>
#include <data/stylesheet.hpp>
DECLARE_TYPEOF_COLLECTION(ColorField::ChoiceP);
......@@ -38,22 +40,31 @@ void ColorValueViewer::draw(RotatedDC& dc) {
dc.DrawRectangle(style().getRect().move(40, 0, -40, 0));
dc.DrawText(color_name, style().getPos() + RealSize(43, 3));
} else {
// do we need clipping?
bool clip = style().left_width < style().width && style().right_width < style().width &&
style().top_width < style().height && style().bottom_width < style().height;
if (clip) {
// clip away the inside of the rectangle
wxRegion r = dc.tr(style().getRect()).toRect();
r.Subtract(dc.tr(RealRect(
style().left + style().left_width,
style().top + style().top_width,
style().width - style().left_width - style().right_width,
style().height - style().top_width - style().bottom_width
)));
dc.getDC().SetClippingRegion(r);
// is there a mask?
loadMask(dc);
if (alpha_mask) {
Image img(alpha_mask->size.x, alpha_mask->size.y);
fill_image(img, value().value());
alpha_mask->setAlpha(img);
dc.DrawImage(img, style().getPos());
} else {
// do we need clipping?
bool clip = style().left_width < style().width && style().right_width < style().width &&
style().top_width < style().height && style().bottom_width < style().height;
if (clip) {
// clip away the inside of the rectangle
wxRegion r = dc.tr(style().getRect()).toRect();
r.Subtract(dc.tr(RealRect(
style().left + style().left_width,
style().top + style().top_width,
style().width - style().left_width - style().right_width,
style().height - style().top_width - style().bottom_width
)));
dc.getDC().SetClippingRegion(r);
}
dc.DrawRoundedRectangle(style().getRect(), style().radius);
if (clip) dc.getDC().DestroyClippingRegion();
}
dc.DrawRoundedRectangle(style().getRect(), style().radius);
if (clip) dc.getDC().DestroyClippingRegion();
}
}
......@@ -61,7 +72,34 @@ bool ColorValueViewer::containsPoint(const RealPoint& p) const {
// distance to each side
double left = p.x - style().left, right = style().left + style().width - p.x - 1;
double top = p.y - style().top, bottom = style().top + style().height - p.y - 1;
return left >= 0 && right >= 0 && top >= 0 && bottom >= 0 && // inside bounding box
(left < style().left_width || right < style().right_width || // inside horizontal border
top < style().top_width || bottom < style().bottom_width); // inside vertical border
if (left < 0 || right < 0 || top < 0 || bottom < 0 || // outside bounding box
(left >= style().left_width && right >= style().right_width && // outside horizontal border
top >= style().top_width && bottom >= style().bottom_width)) { // outside vertical border
return false;
}
// check against mask
if (!style().mask_filename().empty()) {
loadMask(viewer.getRotation());
return !alpha_mask || !alpha_mask->isTransparent((int)left, (int)top);
} else {
return true;
}
}
void ColorValueViewer::onStyleChange() {
alpha_mask = AlphaMaskP();
}
void ColorValueViewer::loadMask(const Rotation& rot) const {
if (style().mask_filename().empty()) return; // no mask
int w = (int) rot.trS(style().width), h = (int) rot.trS(style().height);
if (alpha_mask && alpha_mask->size == wxSize(w,h)) return; // mask loaded and right size
// (re) load the mask
Image image;
InputStreamP image_file = viewer.stylesheet->openIn(style().mask_filename);
if (image.LoadFile(*image_file)) {
Image resampled(w,h);
resample(image, resampled);
alpha_mask = new_shared1<AlphaMask>(resampled);
}
}
......@@ -13,6 +13,8 @@
#include <render/value/viewer.hpp>
#include <data/field/color.hpp>
DECLARE_POINTER_TYPE(AlphaMask);
// ----------------------------------------------------------------------------- : ColorValueViewer
/// Viewer that displays a color value
......@@ -22,6 +24,12 @@ class ColorValueViewer : public ValueViewer {
virtual void draw(RotatedDC& dc);
virtual bool containsPoint(const RealPoint& p) const;
virtual void onStyleChange();
private:
mutable AlphaMaskP alpha_mask;
void loadMask(const Rotation& rot) const;
};
// ----------------------------------------------------------------------------- : EOF
......
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