* moved all the classes actually needed for reading a
vector icon to this place, #ifdef'd out all the editing features (listening, referencing, converting to PropertyObject... etc) * TODO: put into BPrivate namespace... git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18396 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -5,6 +5,7 @@ SubInclude HAIKU_TOP src libs bsd ;
|
||||
#SubInclude HAIKU_TOP src libs edit ;
|
||||
SubInclude HAIKU_TOP src libs fluidsynth ;
|
||||
SubInclude HAIKU_TOP src libs freetype2 ;
|
||||
SubInclude HAIKU_TOP src libs icon ;
|
||||
#SubInclude HAIKU_TOP src libs ncurses ;
|
||||
SubInclude HAIKU_TOP src libs pdflib ;
|
||||
SubInclude HAIKU_TOP src libs png ;
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Icon.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PathContainer.h"
|
||||
#include "Shape.h"
|
||||
#include "Style.h"
|
||||
#include "StyleContainer.h"
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
IconListener::IconListener() {}
|
||||
IconListener::~IconListener() {}
|
||||
#endif
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
Icon::Icon()
|
||||
: fStyles(new (nothrow) StyleContainer()),
|
||||
fPaths(new (nothrow) PathContainer(true)),
|
||||
fShapes(new (nothrow) ShapeContainer())
|
||||
#ifdef ICON_O_MATIC
|
||||
, fListeners(2)
|
||||
#endif
|
||||
{
|
||||
#ifdef ICON_O_MATIC
|
||||
if (fShapes)
|
||||
fShapes->AddListener(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
// constructor
|
||||
Icon::Icon(const Icon& other)
|
||||
: fStyles(new (nothrow) StyleContainer()),
|
||||
fPaths(new (nothrow) PathContainer(true)),
|
||||
fShapes(new (nothrow) ShapeContainer())
|
||||
#ifdef ICON_O_MATIC
|
||||
, fListeners(2)
|
||||
#endif
|
||||
{
|
||||
if (!fStyles || !fPaths || !fShapes)
|
||||
return;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
fShapes->AddListener(this);
|
||||
#endif
|
||||
|
||||
int32 styleCount = other.fStyles->CountStyles();
|
||||
for (int32 i = 0; i < styleCount; i++) {
|
||||
Style* style = other.fStyles->StyleAtFast(i);
|
||||
Style* clone = new (nothrow) Style(*style);
|
||||
if (!clone || !fStyles->AddStyle(clone)) {
|
||||
delete clone;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int32 pathCount = other.fPaths->CountPaths();
|
||||
for (int32 i = 0; i < pathCount; i++) {
|
||||
VectorPath* path = other.fPaths->PathAtFast(i);
|
||||
VectorPath* clone = new (nothrow) VectorPath(*path);
|
||||
if (!clone || !fPaths->AddPath(clone)) {
|
||||
delete clone;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int32 shapeCount = other.fShapes->CountShapes();
|
||||
for (int32 i = 0; i < shapeCount; i++) {
|
||||
Shape* shape = other.fShapes->ShapeAtFast(i);
|
||||
Shape* clone = new (nothrow) Shape(*shape);
|
||||
if (!clone || !fShapes->AddShape(clone)) {
|
||||
delete clone;
|
||||
return;
|
||||
}
|
||||
// the cloned shape references styles and paths in
|
||||
// the "other" icon, replace them with "local" styles
|
||||
// and paths
|
||||
int32 styleIndex = other.fStyles->IndexOf(shape->Style());
|
||||
clone->SetStyle(fStyles->StyleAt(styleIndex));
|
||||
|
||||
clone->Paths()->MakeEmpty();
|
||||
pathCount = shape->Paths()->CountPaths();
|
||||
for (int32 j = 0; j < pathCount; j++) {
|
||||
VectorPath* remote = shape->Paths()->PathAtFast(j);
|
||||
int32 index = other.fPaths->IndexOf(remote);
|
||||
VectorPath* local = fPaths->PathAt(index);
|
||||
if (!local) {
|
||||
printf("failed to match remote and "
|
||||
"local paths while cloning icon\n");
|
||||
continue;
|
||||
}
|
||||
if (!clone->Paths()->AddPath(local)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// destructor
|
||||
Icon::~Icon()
|
||||
{
|
||||
if (fShapes) {
|
||||
fShapes->MakeEmpty();
|
||||
#ifdef ICON_O_MATIC
|
||||
fShapes->RemoveListener(this);
|
||||
#endif
|
||||
delete fShapes;
|
||||
}
|
||||
delete fPaths;
|
||||
delete fStyles;
|
||||
}
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// ShapeAdded
|
||||
void
|
||||
Icon::ShapeAdded(Shape* shape, int32 index)
|
||||
{
|
||||
shape->AddObserver(this);
|
||||
_NotifyAreaInvalidated(shape->Bounds(true));
|
||||
}
|
||||
|
||||
// ShapeRemoved
|
||||
void
|
||||
Icon::ShapeRemoved(Shape* shape)
|
||||
{
|
||||
shape->RemoveObserver(this);
|
||||
_NotifyAreaInvalidated(shape->Bounds(true));
|
||||
}
|
||||
|
||||
// ObjectChanged
|
||||
void
|
||||
Icon::ObjectChanged(const Observable* object)
|
||||
{
|
||||
const Shape* shape = dynamic_cast<const Shape*>(object);
|
||||
if (shape) {
|
||||
BRect area = shape->LastBounds();
|
||||
area = area | shape->Bounds(true);
|
||||
area.InsetBy(-1, -1);
|
||||
_NotifyAreaInvalidated(area);
|
||||
}
|
||||
}
|
||||
|
||||
// AddListener
|
||||
bool
|
||||
Icon::AddListener(IconListener* listener)
|
||||
{
|
||||
if (listener && !fListeners.HasItem((void*)listener))
|
||||
return fListeners.AddItem((void*)listener);
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemoveListener
|
||||
bool
|
||||
Icon::RemoveListener(IconListener* listener)
|
||||
{
|
||||
return fListeners.RemoveItem((void*)listener);
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
|
||||
// Clone
|
||||
Icon*
|
||||
Icon::Clone() const
|
||||
{
|
||||
return new (nothrow) Icon(*this);
|
||||
}
|
||||
|
||||
// MakeEmpty
|
||||
void
|
||||
Icon::MakeEmpty()
|
||||
{
|
||||
fShapes->MakeEmpty();
|
||||
fPaths->MakeEmpty();
|
||||
fStyles->MakeEmpty();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// _NotifyAreaInvalidated
|
||||
void
|
||||
Icon::_NotifyAreaInvalidated(const BRect& area) const
|
||||
{
|
||||
BList listeners(fListeners);
|
||||
int32 count = listeners.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
IconListener* listener
|
||||
= (IconListener*)listeners.ItemAtFast(i);
|
||||
listener->AreaInvalidated(area);
|
||||
}
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef ICON_H
|
||||
#define ICON_H
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
#include <List.h>
|
||||
|
||||
# include "Observer.h"
|
||||
#else
|
||||
# include <SupportDefs.h>
|
||||
#endif
|
||||
#include "ShapeContainer.h"
|
||||
|
||||
class BRect;
|
||||
class PathContainer;
|
||||
class StyleContainer;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
class IconListener {
|
||||
public:
|
||||
IconListener();
|
||||
virtual ~IconListener();
|
||||
|
||||
virtual void AreaInvalidated(const BRect& area) = 0;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
class Icon : public ShapeContainerListener,
|
||||
public Observer {
|
||||
#else
|
||||
class Icon {
|
||||
#endif
|
||||
|
||||
public:
|
||||
Icon();
|
||||
Icon(const Icon& other);
|
||||
virtual ~Icon();
|
||||
|
||||
StyleContainer* Styles() const
|
||||
{ return fStyles; }
|
||||
PathContainer* Paths() const
|
||||
{ return fPaths; }
|
||||
ShapeContainer* Shapes() const
|
||||
{ return fShapes; }
|
||||
|
||||
Icon* Clone() const;
|
||||
void MakeEmpty();
|
||||
|
||||
private:
|
||||
|
||||
StyleContainer* fStyles;
|
||||
PathContainer* fPaths;
|
||||
ShapeContainer* fShapes;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
public:
|
||||
// ShapeContainerListener interface
|
||||
virtual void ShapeAdded(Shape* shape, int32 index);
|
||||
virtual void ShapeRemoved(Shape* shape);
|
||||
|
||||
// Observer interface
|
||||
virtual void ObjectChanged(const Observable* object);
|
||||
|
||||
// Icon
|
||||
bool AddListener(IconListener* listener);
|
||||
bool RemoveListener(IconListener* listener);
|
||||
|
||||
private:
|
||||
void _NotifyAreaInvalidated(
|
||||
const BRect& area) const;
|
||||
BList fListeners;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // ICON_H
|
||||
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "IconRenderer.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <List.h>
|
||||
|
||||
#include <agg_span_gradient.h>
|
||||
#include <agg_span_interpolator_linear.h>
|
||||
|
||||
#include "Gradient.h"
|
||||
#include "Icon.h"
|
||||
#include "Shape.h"
|
||||
#include "ShapeContainer.h"
|
||||
#include "Style.h"
|
||||
#include "VectorPath.h"
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
class StyleHandler {
|
||||
struct StyleItem {
|
||||
Style* style;
|
||||
Transformation transformation;
|
||||
};
|
||||
|
||||
public:
|
||||
StyleHandler(::GammaTable& gammaTable)
|
||||
: fStyles(20),
|
||||
fGammaTable(gammaTable),
|
||||
fTransparent(0, 0, 0, 0),
|
||||
fColor(0, 0, 0, 0)
|
||||
{}
|
||||
|
||||
~StyleHandler()
|
||||
{
|
||||
int32 count = fStyles.CountItems();
|
||||
for (int32 i = 0; i < count; i++)
|
||||
delete (StyleItem*)fStyles.ItemAtFast(i);
|
||||
}
|
||||
|
||||
bool is_solid(unsigned styleIndex) const
|
||||
{
|
||||
StyleItem* styleItem = (StyleItem*)fStyles.ItemAt(styleIndex);
|
||||
if (!styleItem)
|
||||
return true;
|
||||
|
||||
return styleItem->style->Gradient() == NULL;
|
||||
}
|
||||
|
||||
const agg::rgba8& color(unsigned styleIndex);
|
||||
|
||||
void generate_span(agg::rgba8* span, int x, int y,
|
||||
unsigned len, unsigned styleIndex);
|
||||
|
||||
bool AddStyle(Style* style, const Transformation& transformation)
|
||||
{
|
||||
if (!style)
|
||||
return false;
|
||||
StyleItem* item = new (nothrow) StyleItem;
|
||||
if (!item)
|
||||
return false;
|
||||
item->style = style;
|
||||
// if the style uses a gradient, the transformation
|
||||
// is based on the gradient transformation
|
||||
if (Gradient* gradient = style->Gradient()) {
|
||||
item->transformation = *gradient;
|
||||
item->transformation.multiply(transformation);
|
||||
} else {
|
||||
item->transformation = transformation;
|
||||
}
|
||||
item->transformation.invert();
|
||||
return fStyles.AddItem((void*)item);
|
||||
}
|
||||
|
||||
private:
|
||||
template<class GradientFunction>
|
||||
void _GenerateGradient(agg::rgba8* span, int x, int y, unsigned len,
|
||||
GradientFunction function, int32 start, int32 end,
|
||||
const agg::rgba8* gradientColors,
|
||||
Transformation& gradientTransform);
|
||||
|
||||
BList fStyles;
|
||||
::GammaTable& fGammaTable;
|
||||
agg::rgba8 fTransparent;
|
||||
agg::rgba8 fColor;
|
||||
};
|
||||
|
||||
// color
|
||||
const agg::rgba8&
|
||||
StyleHandler::color(unsigned styleIndex)
|
||||
{
|
||||
StyleItem* styleItem = (StyleItem*)fStyles.ItemAt(styleIndex);
|
||||
if (!styleItem) {
|
||||
printf("no style at index: %d!\n", styleIndex);
|
||||
return fTransparent;
|
||||
}
|
||||
|
||||
const rgb_color& c = styleItem->style->Color();
|
||||
fColor = agg::rgba8(fGammaTable.dir(c.red),
|
||||
fGammaTable.dir(c.green),
|
||||
fGammaTable.dir(c.blue),
|
||||
c.alpha);
|
||||
fColor.premultiply();
|
||||
return fColor;
|
||||
}
|
||||
|
||||
// generate_span
|
||||
void
|
||||
StyleHandler::generate_span(agg::rgba8* span, int x, int y,
|
||||
unsigned len, unsigned styleIndex)
|
||||
{
|
||||
StyleItem* styleItem = (StyleItem*)fStyles.ItemAt(styleIndex);
|
||||
if (!styleItem || !styleItem->style->Gradient()) {
|
||||
printf("no style/gradient at index: %d!\n", styleIndex);
|
||||
// TODO: memset() span?
|
||||
return;
|
||||
}
|
||||
|
||||
Style* style = styleItem->style;
|
||||
Gradient* gradient = style->Gradient();
|
||||
const agg::rgba8* colors = style->GammaCorrectedColors(fGammaTable);
|
||||
|
||||
switch (gradient->Type()) {
|
||||
case GRADIENT_LINEAR: {
|
||||
agg::gradient_x function;
|
||||
_GenerateGradient(span, x, y, len, function, -64, 64, colors,
|
||||
styleItem->transformation);
|
||||
break;
|
||||
}
|
||||
case GRADIENT_CIRCULAR: {
|
||||
agg::gradient_radial function;
|
||||
_GenerateGradient(span, x, y, len, function, 0, 64, colors,
|
||||
styleItem->transformation);
|
||||
break;
|
||||
}
|
||||
case GRADIENT_DIAMONT: {
|
||||
agg::gradient_diamond function;
|
||||
_GenerateGradient(span, x, y, len, function, 0, 64, colors,
|
||||
styleItem->transformation);
|
||||
break;
|
||||
}
|
||||
case GRADIENT_CONIC: {
|
||||
agg::gradient_conic function;
|
||||
_GenerateGradient(span, x, y, len, function, 0, 64, colors,
|
||||
styleItem->transformation);
|
||||
break;
|
||||
}
|
||||
case GRADIENT_XY: {
|
||||
agg::gradient_xy function;
|
||||
_GenerateGradient(span, x, y, len, function, 0, 64, colors,
|
||||
styleItem->transformation);
|
||||
break;
|
||||
}
|
||||
case GRADIENT_SQRT_XY: {
|
||||
agg::gradient_sqrt_xy function;
|
||||
_GenerateGradient(span, x, y, len, function, 0, 64, colors,
|
||||
styleItem->transformation);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _GenerateGradient
|
||||
template<class GradientFunction>
|
||||
void
|
||||
StyleHandler::_GenerateGradient(agg::rgba8* span, int x, int y, unsigned len,
|
||||
GradientFunction function,
|
||||
int32 start, int32 end,
|
||||
const agg::rgba8* gradientColors,
|
||||
Transformation& gradientTransform)
|
||||
|
||||
{
|
||||
typedef agg::pod_auto_array<agg::rgba8, 256> ColorArray;
|
||||
typedef agg::span_interpolator_linear<> Interpolator;
|
||||
typedef agg::span_gradient<agg::rgba8,
|
||||
Interpolator,
|
||||
GradientFunction,
|
||||
ColorArray> GradientGenerator;
|
||||
|
||||
Interpolator interpolator(gradientTransform);
|
||||
|
||||
ColorArray array(gradientColors);
|
||||
GradientGenerator gradientGenerator(interpolator,
|
||||
function,
|
||||
array,
|
||||
start, end);
|
||||
|
||||
gradientGenerator.generate(span, x, y, len);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
class HintingTransformer {
|
||||
public:
|
||||
|
||||
void transform(double* x, double* y) const
|
||||
{
|
||||
*x = floor(*x + 0.5);
|
||||
*y = floor(*y + 0.5);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
IconRenderer::IconRenderer(BBitmap* bitmap)
|
||||
: fBitmap(bitmap),
|
||||
fBackground(NULL),
|
||||
fBackgroundColor(0, 0, 0, 0),
|
||||
fIcon(NULL),
|
||||
|
||||
fGammaTable(2.2),
|
||||
|
||||
fRenderingBuffer(),
|
||||
fPixelFormat(fRenderingBuffer),
|
||||
fPixelFormatPre(fRenderingBuffer),
|
||||
fBaseRenderer(fPixelFormat),
|
||||
fBaseRendererPre(fPixelFormatPre),
|
||||
|
||||
fScanline(),
|
||||
fBinaryScanline(),
|
||||
fSpanAllocator(),
|
||||
|
||||
fRasterizer(),
|
||||
|
||||
fGlobalTransform()
|
||||
{
|
||||
// attach rendering buffer to bitmap
|
||||
fRenderingBuffer.attach((uint8*)bitmap->Bits(),
|
||||
bitmap->Bounds().IntegerWidth() + 1,
|
||||
bitmap->Bounds().IntegerHeight() + 1,
|
||||
bitmap->BytesPerRow());
|
||||
|
||||
fBaseRendererPre.clip_box(0,
|
||||
0,
|
||||
fBitmap->Bounds().IntegerWidth(),
|
||||
fBitmap->Bounds().IntegerHeight());
|
||||
}
|
||||
|
||||
// destructor
|
||||
IconRenderer::~IconRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
// SetIcon
|
||||
void
|
||||
IconRenderer::SetIcon(const Icon* icon)
|
||||
{
|
||||
if (fIcon == icon)
|
||||
return;
|
||||
|
||||
fIcon = icon;
|
||||
// TODO: ... ?
|
||||
}
|
||||
|
||||
// Render
|
||||
void
|
||||
IconRenderer::Render()
|
||||
{
|
||||
_Render(fBitmap->Bounds());
|
||||
}
|
||||
|
||||
// Render
|
||||
void
|
||||
IconRenderer::Render(const BRect& area)
|
||||
{
|
||||
_Render(fBitmap->Bounds() & area);
|
||||
}
|
||||
|
||||
//SetScale
|
||||
void
|
||||
IconRenderer::SetScale(double scale)
|
||||
{
|
||||
fGlobalTransform.reset();
|
||||
fGlobalTransform.multiply(agg::trans_affine_scaling(scale));
|
||||
}
|
||||
|
||||
//SetBackground
|
||||
void
|
||||
IconRenderer::SetBackground(const BBitmap* background)
|
||||
{
|
||||
fBackground = background;
|
||||
}
|
||||
|
||||
//SetBackground
|
||||
void
|
||||
IconRenderer::SetBackground(const agg::rgba8& background)
|
||||
{
|
||||
fBackgroundColor.r = fGammaTable.dir(background.r);
|
||||
fBackgroundColor.g = fGammaTable.dir(background.g);
|
||||
fBackgroundColor.b = fGammaTable.dir(background.b);
|
||||
fBackgroundColor.a = background.a;
|
||||
}
|
||||
|
||||
// Demultiply
|
||||
void
|
||||
IconRenderer::Demultiply()
|
||||
{
|
||||
uint8* bits = (uint8*)fBitmap->Bits();
|
||||
uint32 bpr = fBitmap->BytesPerRow();
|
||||
uint32 width = fBitmap->Bounds().IntegerWidth() + 1;
|
||||
uint32 height = fBitmap->Bounds().IntegerHeight() + 1;
|
||||
|
||||
for (uint32 y = 0; y < height; y++) {
|
||||
uint8* b = bits;
|
||||
for (uint32 x = 0; x < width; x++) {
|
||||
if (b[3] < 255 && b[3] > 0) {
|
||||
b[0] = (uint8)((int)b[0] * 255 / b[3]);
|
||||
b[1] = (uint8)((int)b[1] * 255 / b[3]);
|
||||
b[2] = (uint8)((int)b[2] * 255 / b[3]);
|
||||
}
|
||||
b += 4;
|
||||
}
|
||||
bits += bpr;
|
||||
}
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
typedef agg::conv_transform<VertexSource, Transformation> ScaledPath;
|
||||
typedef agg::conv_transform<ScaledPath, HintingTransformer> HintedPath;
|
||||
|
||||
// _Render
|
||||
void
|
||||
IconRenderer::_Render(const BRect& r)
|
||||
{
|
||||
if (!fIcon)
|
||||
return;
|
||||
|
||||
// TODO: fix clip box for "clear" and "apply_gamma_inv"
|
||||
// fBaseRendererPre.clip_box((int)floorf(r.left),
|
||||
// (int)floorf(r.top),
|
||||
// (int)ceilf(r.right),
|
||||
// (int)ceilf(r.bottom));
|
||||
|
||||
if (fBackground)
|
||||
memcpy(fBitmap->Bits(), fBackground->Bits(), fBitmap->BitsLength());
|
||||
else
|
||||
fBaseRendererPre.clear(fBackgroundColor);
|
||||
|
||||
//bigtime_t start = system_time();
|
||||
StyleHandler styleHandler(fGammaTable);
|
||||
|
||||
fRasterizer.reset();
|
||||
// iterate over the shapes in the icon,
|
||||
// add the vector paths to the rasterizer
|
||||
// and associate each shapes style
|
||||
int32 shapeCount = fIcon->Shapes()->CountShapes();
|
||||
int32 styleIndex = 0;
|
||||
for (int32 i = 0; i < shapeCount; i++) {
|
||||
Shape* shape = fIcon->Shapes()->ShapeAtFast(i);
|
||||
|
||||
Transformation transform(*shape);
|
||||
transform.multiply(fGlobalTransform);
|
||||
// NOTE: this works only because "agg::trans_affine",
|
||||
// "Transformable" and "Transformation" are all the
|
||||
// same thing
|
||||
|
||||
// don't render shape if the Level Of Detail falls
|
||||
// out of range
|
||||
if (transform.scale() <= shape->MinVisibilityScale()
|
||||
|| transform.scale() > shape->MaxVisibilityScale())
|
||||
continue;
|
||||
|
||||
Style* style = shape->Style();
|
||||
if (!style)
|
||||
continue;
|
||||
|
||||
// add the style either with global transformation or with
|
||||
// the shapes transformation, depending on wether there
|
||||
// is a gradient and its settings
|
||||
Gradient* gradient = style->Gradient();
|
||||
bool styleAdded = false;
|
||||
if (gradient && !gradient->InheritTransformation()) {
|
||||
styleAdded = styleHandler.AddStyle(shape->Style(),
|
||||
fGlobalTransform);
|
||||
} else {
|
||||
styleAdded = styleHandler.AddStyle(shape->Style(),
|
||||
transform);
|
||||
}
|
||||
|
||||
if (!styleAdded) {
|
||||
printf("IconRenderer::_Render() - out of memory\n");
|
||||
break;
|
||||
}
|
||||
fRasterizer.styles(styleIndex, -1);
|
||||
styleIndex++;
|
||||
|
||||
// global scale
|
||||
ScaledPath scaledPath(shape->VertexSource(), transform);
|
||||
if (shape->Hinting()) {
|
||||
// additional hinting
|
||||
HintingTransformer hinter;
|
||||
HintedPath hintedPath(scaledPath, hinter);
|
||||
fRasterizer.add_path(hintedPath);
|
||||
} else {
|
||||
fRasterizer.add_path(scaledPath);
|
||||
}
|
||||
}
|
||||
|
||||
agg::render_scanlines_compound(fRasterizer,
|
||||
fScanline,
|
||||
fBinaryScanline,
|
||||
fBaseRendererPre,
|
||||
fSpanAllocator,
|
||||
styleHandler);
|
||||
|
||||
if (fGammaTable.gamma() != 1.0)
|
||||
fPixelFormat.apply_gamma_inv(fGammaTable);
|
||||
|
||||
//if (fRenderingBuffer.width() == 64)
|
||||
//printf("rendering 64x64: %lld\n", system_time() - start);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef ICON_RENDERER_H
|
||||
#define ICON_RENDERER_H
|
||||
|
||||
#include <agg_gamma_lut.h>
|
||||
#include <agg_pixfmt_rgba.h>
|
||||
#include <agg_rasterizer_compound_aa.h>
|
||||
#include <agg_rendering_buffer.h>
|
||||
#include <agg_renderer_scanline.h>
|
||||
#include <agg_scanline_bin.h>
|
||||
#include <agg_scanline_u.h>
|
||||
#include <agg_span_allocator.h>
|
||||
#include <agg_trans_affine.h>
|
||||
|
||||
class BBitmap;
|
||||
class BRect;
|
||||
class Icon;
|
||||
|
||||
typedef agg::gamma_lut
|
||||
<agg::int8u, agg::int8u> GammaTable;
|
||||
|
||||
typedef agg::rendering_buffer RenderingBuffer;
|
||||
typedef agg::pixfmt_bgra32 PixelFormat;
|
||||
typedef agg::pixfmt_bgra32_pre PixelFormatPre;
|
||||
typedef agg::renderer_base<PixelFormat> BaseRenderer;
|
||||
typedef agg::renderer_base<PixelFormatPre> BaseRendererPre;
|
||||
|
||||
typedef agg::scanline_u8 Scanline;
|
||||
typedef agg::scanline_bin BinaryScanline;
|
||||
typedef agg::span_allocator<agg::rgba8> SpanAllocator;
|
||||
typedef agg::rasterizer_compound_aa
|
||||
<agg::rasterizer_sl_clip_dbl> CompoundRasterizer;
|
||||
|
||||
typedef agg::trans_affine Transformation;
|
||||
|
||||
class IconRenderer {
|
||||
public:
|
||||
IconRenderer(BBitmap* bitmap);
|
||||
virtual ~IconRenderer();
|
||||
|
||||
void SetIcon(const Icon* icon);
|
||||
|
||||
void Render();
|
||||
void Render(const BRect& area);
|
||||
|
||||
void SetScale(double scale);
|
||||
void SetBackground(const BBitmap* background);
|
||||
// background is not copied,
|
||||
// ownership stays with the caller
|
||||
// colorspace and size need to
|
||||
// be the same as bitmap passed
|
||||
// to constructor
|
||||
void SetBackground(const agg::rgba8& color);
|
||||
// used when no background bitmap
|
||||
// is set
|
||||
|
||||
const ::GammaTable& GammaTable() const
|
||||
{ return fGammaTable; }
|
||||
|
||||
void Demultiply();
|
||||
|
||||
private:
|
||||
void _Render(const BRect& area);
|
||||
|
||||
BBitmap* fBitmap;
|
||||
const BBitmap* fBackground;
|
||||
agg::rgba8 fBackgroundColor;
|
||||
const Icon* fIcon;
|
||||
|
||||
::GammaTable fGammaTable;
|
||||
|
||||
RenderingBuffer fRenderingBuffer;
|
||||
PixelFormat fPixelFormat;
|
||||
PixelFormatPre fPixelFormatPre;
|
||||
BaseRenderer fBaseRenderer;
|
||||
BaseRendererPre fBaseRendererPre;
|
||||
|
||||
Scanline fScanline;
|
||||
BinaryScanline fBinaryScanline;
|
||||
SpanAllocator fSpanAllocator;
|
||||
|
||||
CompoundRasterizer fRasterizer;
|
||||
|
||||
Transformation fGlobalTransform;
|
||||
};
|
||||
|
||||
#endif // ICON_RENDERER_H
|
||||
@@ -0,0 +1,58 @@
|
||||
SubDir HAIKU_TOP src libs icon ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
AddSubDirSupportedPlatforms libbe_test ;
|
||||
|
||||
# source directories
|
||||
local sourceDirs =
|
||||
flat_icon
|
||||
shape
|
||||
style
|
||||
transformable
|
||||
transformer
|
||||
;
|
||||
|
||||
local sourceDir ;
|
||||
for sourceDir in $(sourceDirs) {
|
||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src libs icon $(sourceDir) ] ;
|
||||
}
|
||||
|
||||
# system headers
|
||||
UseLibraryHeaders agg ;
|
||||
|
||||
UsePrivateHeaders shared ;
|
||||
|
||||
StaticLibrary libicon.a :
|
||||
# flat_icon
|
||||
FlatIconFormat.cpp
|
||||
FlatIconImporter.cpp
|
||||
LittleEndianBuffer.cpp
|
||||
PathCommandQueue.cpp
|
||||
|
||||
# shape
|
||||
PathContainer.cpp
|
||||
Shape.cpp
|
||||
ShapeContainer.cpp
|
||||
VectorPath.cpp
|
||||
|
||||
# style
|
||||
Gradient.cpp
|
||||
Style.cpp
|
||||
StyleContainer.cpp
|
||||
|
||||
# transformable
|
||||
Transformable.cpp
|
||||
|
||||
# transformer
|
||||
AffineTransformer.cpp
|
||||
ContourTransformer.cpp
|
||||
PathSource.cpp
|
||||
PerspectiveTransformer.cpp
|
||||
StrokeTransformer.cpp
|
||||
Transformer.cpp
|
||||
TransformerFactory.cpp
|
||||
|
||||
Icon.cpp
|
||||
IconRenderer.cpp
|
||||
;
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "FlatIconFormat.h"
|
||||
|
||||
#include "LittleEndianBuffer.h"
|
||||
|
||||
const uint32 FLAT_ICON_MAGIC = 'ficn';
|
||||
|
||||
const char* kVectorAttrNodeName = "BEOS:I:STD_ICON";
|
||||
const char* kVectorAttrMimeName = "META:I:STD_ICON";
|
||||
|
||||
// read_coord
|
||||
bool
|
||||
read_coord(LittleEndianBuffer& buffer, float& coord)
|
||||
{
|
||||
uint8 value;
|
||||
if (!buffer.Read(value))
|
||||
return false;
|
||||
|
||||
if (value & 128) {
|
||||
// high bit set, the next byte is part of the coord
|
||||
uint8 lowValue;
|
||||
if (!buffer.Read(lowValue))
|
||||
return false;
|
||||
value &= 127;
|
||||
uint16 coordValue = (value << 8) | lowValue;
|
||||
coord = (float)coordValue / 102.0 - 128.0;
|
||||
} else {
|
||||
// simple coord
|
||||
coord = (float)value - 32.0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// write_coord
|
||||
bool
|
||||
write_coord(LittleEndianBuffer& buffer, float coord)
|
||||
{
|
||||
// clamp coord
|
||||
if (coord < -128.0)
|
||||
coord = -128.0;
|
||||
if (coord > 192.0)
|
||||
coord = 192.0;
|
||||
|
||||
if (int(coord * 100.0) == (int)coord * 100
|
||||
&& coord >= - 32.0 && coord <= 96.0) {
|
||||
// saving coord in 7 bit is sufficient
|
||||
uint8 value = (uint8)(coord + 32.0);
|
||||
return buffer.Write(value);
|
||||
} else {
|
||||
// needing to save coord in 15 bits
|
||||
uint16 value = (uint16)((coord + 128.0) * 102.0);
|
||||
// set high bit to indicate there is only one byte
|
||||
value |= 32768;
|
||||
uint8 highValue = value >> 8;
|
||||
uint8 lowValue = value & 255;
|
||||
return buffer.Write(highValue) && buffer.Write(lowValue);
|
||||
}
|
||||
}
|
||||
|
||||
// read_float_24
|
||||
bool
|
||||
read_float_24(LittleEndianBuffer& buffer, float& _value)
|
||||
{
|
||||
uint8 bufferValue[3];
|
||||
if (!buffer.Read(bufferValue[0]) || !buffer.Read(bufferValue[1])
|
||||
|| !buffer.Read(bufferValue[2]))
|
||||
return false;
|
||||
|
||||
int shortValue = (bufferValue[0] << 16)
|
||||
| (bufferValue[1] << 8) | bufferValue[2];
|
||||
|
||||
int sign = (shortValue & 0x800000) >> 23;
|
||||
int exponent = ((shortValue & 0x7e0000) >> 17) - 32;
|
||||
int mantissa = (shortValue & 0x01ffff) << 6;
|
||||
|
||||
if (shortValue == 0)
|
||||
_value = 0.0;
|
||||
else {
|
||||
uint32 value = (sign << 31) | ((exponent + 127) << 23) | mantissa;
|
||||
|
||||
_value = (float&)value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// write_float_24
|
||||
bool
|
||||
write_float_24(LittleEndianBuffer& buffer, float _value)
|
||||
{
|
||||
// 1 bit sign
|
||||
// 6 bit exponent
|
||||
// 17 bit mantissa
|
||||
// TODO: fixme for non-IEEE 754 architectures
|
||||
uint32 value = (uint32&)_value;
|
||||
|
||||
int sign = (value & 0x80000000) >> 31;
|
||||
int exponent = ((value & 0x7f800000) >> 23) - 127;
|
||||
int mantissa = value & 0x007fffff;
|
||||
|
||||
if (exponent >= 32 || exponent < -32) {
|
||||
uint8 zero = 0;
|
||||
return buffer.Write(zero) && buffer.Write(zero)
|
||||
&& buffer.Write(zero);
|
||||
}
|
||||
|
||||
int shortValue = (sign << 23)
|
||||
| ((exponent + 32) << 17)
|
||||
| (mantissa >> 6);
|
||||
|
||||
return buffer.Write((uint8)(shortValue >> 16))
|
||||
&& buffer.Write((uint8)((shortValue >> 8) & 0xff))
|
||||
&& buffer.Write((uint8)(shortValue & 0xff));
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef FLAT_ICON_FORMAT_H
|
||||
#define FLAT_ICON_FORMAT_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
extern const uint32 FLAT_ICON_MAGIC;
|
||||
extern const char* kVectorAttrNodeName;
|
||||
extern const char* kVectorAttrMimeName;
|
||||
|
||||
enum {
|
||||
TAG_STYLE_SOLID_COLOR = 1,
|
||||
TAG_STYLE_GRADIENT = 2,
|
||||
TAG_STYLE_SOLID_COLOR_NO_ALPHA = 3,
|
||||
|
||||
TAG_SHAPE_PATH_SOURCE = 10,
|
||||
|
||||
TAG_TRANSFORMER_AFFINE = 20,
|
||||
TAG_TRANSFORMER_CONTOUR = 21,
|
||||
TAG_TRANSFORMER_PERSPECTIVE = 22,
|
||||
TAG_TRANSFORMER_STROKE = 23,
|
||||
};
|
||||
|
||||
enum {
|
||||
GRADIENT_FLAG_TRANSFORM = 1 << 1,
|
||||
GRADIENT_FLAG_NO_ALPHA = 1 << 2,
|
||||
GRADIENT_FLAG_16_BIT_COLORS = 1 << 3, // not yet used
|
||||
};
|
||||
|
||||
enum {
|
||||
PATH_FLAGS_CLOSED = 1 << 1,
|
||||
PATH_FLAGS_USES_COMMANDS = 1 << 2,
|
||||
PATH_FLAGS_NO_CURVES = 1 << 3,
|
||||
};
|
||||
|
||||
enum {
|
||||
PATH_COMMAND_H_LINE = 0,
|
||||
PATH_COMMAND_V_LINE = 1,
|
||||
PATH_COMMAND_LINE = 2,
|
||||
PATH_COMMAND_CURVE = 3,
|
||||
};
|
||||
|
||||
enum {
|
||||
SHAPE_FLAG_TRANSFORM = 1 << 1,
|
||||
SHAPE_FLAG_HINTING = 1 << 2,
|
||||
SHAPE_FLAG_LOD_SCALE = 1 << 3,
|
||||
SHAPE_FLAG_HAS_TRANSFORMERS = 1 << 4,
|
||||
SHAPE_FLAG_TRANSLATION = 1 << 5,
|
||||
};
|
||||
|
||||
// utility functions
|
||||
|
||||
class LittleEndianBuffer;
|
||||
|
||||
bool read_coord(LittleEndianBuffer& buffer, float& coord);
|
||||
bool write_coord(LittleEndianBuffer& buffer, float coord);
|
||||
|
||||
bool read_float_24(LittleEndianBuffer& buffer, float& value);
|
||||
bool write_float_24(LittleEndianBuffer& buffer, float value);
|
||||
|
||||
#endif // FLAT_ICON_FORMAT_H
|
||||
@@ -0,0 +1,594 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "FlatIconImporter.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Archivable.h>
|
||||
#include <DataIO.h>
|
||||
#include <Message.h>
|
||||
|
||||
#include "AffineTransformer.h"
|
||||
#include "AutoDeleter.h"
|
||||
#include "ContourTransformer.h"
|
||||
#include "FlatIconFormat.h"
|
||||
#include "Gradient.h"
|
||||
#include "Icon.h"
|
||||
#include "LittleEndianBuffer.h"
|
||||
#include "PathCommandQueue.h"
|
||||
#include "PathContainer.h"
|
||||
#include "PerspectiveTransformer.h"
|
||||
#include "Shape.h"
|
||||
#include "StrokeTransformer.h"
|
||||
#include "Style.h"
|
||||
#include "StyleContainer.h"
|
||||
#include "VectorPath.h"
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// constructor
|
||||
FlatIconImporter::FlatIconImporter()
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
FlatIconImporter::~FlatIconImporter()
|
||||
{
|
||||
}
|
||||
|
||||
// Import
|
||||
status_t
|
||||
FlatIconImporter::Import(Icon* icon, BPositionIO* stream)
|
||||
{
|
||||
// seek around in the stream to figure out the size
|
||||
off_t size = stream->Seek(0, SEEK_END);
|
||||
if (stream->Seek(0, SEEK_SET) != 0)
|
||||
return B_ERROR;
|
||||
|
||||
// we chicken out on anything larger than 256k
|
||||
if (size <= 0 || size > 256 * 1024)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// read the entire stream into a buffer
|
||||
LittleEndianBuffer buffer(size);
|
||||
if (!buffer.Buffer())
|
||||
return B_NO_MEMORY;
|
||||
|
||||
if (stream->Read(buffer.Buffer(), size) != size)
|
||||
return B_ERROR;
|
||||
|
||||
status_t ret = _ParseSections(buffer, icon);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Import
|
||||
status_t
|
||||
FlatIconImporter::Import(Icon* icon, uint8* _buffer, size_t size)
|
||||
{
|
||||
if (!_buffer)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// attach LittleEndianBuffer to buffer
|
||||
LittleEndianBuffer buffer(_buffer, size);
|
||||
|
||||
return _ParseSections(buffer, icon);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _ParseSections
|
||||
status_t
|
||||
FlatIconImporter::_ParseSections(LittleEndianBuffer& buffer, Icon* icon)
|
||||
{
|
||||
// test if this is an icon at all
|
||||
uint32 magic;
|
||||
if (!buffer.Read(magic) || magic != FLAT_ICON_MAGIC)
|
||||
return B_ERROR;
|
||||
|
||||
// styles
|
||||
StyleContainer* styles = icon->Styles();
|
||||
status_t ret = _ParseStyles(buffer, styles);
|
||||
if (ret < B_OK) {
|
||||
printf("FlatIconImporter::_ParseSections() - "
|
||||
"error parsing styles: %s\n", strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// paths
|
||||
PathContainer* paths = icon->Paths();
|
||||
ret = _ParsePaths(buffer, paths);
|
||||
if (ret < B_OK) {
|
||||
printf("FlatIconImporter::_ParseSections() - "
|
||||
"error parsing paths: %s\n", strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// shapes
|
||||
ret = _ParseShapes(buffer, styles, paths, icon->Shapes());
|
||||
if (ret < B_OK) {
|
||||
printf("FlatIconImporter::_ParseSections() - "
|
||||
"error parsing shapes: %s\n", strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// _ReadTransformable
|
||||
static bool
|
||||
_ReadTransformable(LittleEndianBuffer& buffer, Transformable* transformable)
|
||||
{
|
||||
int32 matrixSize = Transformable::matrix_size;
|
||||
double matrix[matrixSize];
|
||||
for (int32 i = 0; i < matrixSize; i++) {
|
||||
float value;
|
||||
if (!read_float_24(buffer, value))
|
||||
return false;
|
||||
matrix[i] = value;
|
||||
}
|
||||
transformable->LoadFrom(matrix);
|
||||
return true;
|
||||
}
|
||||
|
||||
// _ReadTranslation
|
||||
static bool
|
||||
_ReadTranslation(LittleEndianBuffer& buffer, Transformable* transformable)
|
||||
{
|
||||
BPoint t;
|
||||
if (read_coord(buffer, t.x) && read_coord(buffer, t.y)) {
|
||||
transformable->TranslateBy(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// _ReadColorStyle
|
||||
static Style*
|
||||
_ReadColorStyle(LittleEndianBuffer& buffer, bool alpha)
|
||||
{
|
||||
rgb_color color;
|
||||
if (alpha) {
|
||||
if (!buffer.Read((uint32&)color))
|
||||
return NULL;
|
||||
} else {
|
||||
color.alpha = 255;
|
||||
if (!buffer.Read(color.red)
|
||||
|| !buffer.Read(color.green)
|
||||
|| !buffer.Read(color.blue))
|
||||
return NULL;
|
||||
}
|
||||
return new (nothrow) Style(color);
|
||||
}
|
||||
|
||||
// _ReadGradientStyle
|
||||
static Style*
|
||||
_ReadGradientStyle(LittleEndianBuffer& buffer)
|
||||
{
|
||||
Style* style = new (nothrow) Style();
|
||||
if (!style)
|
||||
return NULL;
|
||||
|
||||
ObjectDeleter<Style> styleDeleter(style);
|
||||
|
||||
uint8 gradientType;
|
||||
uint8 gradientFlags;
|
||||
uint8 gradientStopCount;
|
||||
if (!buffer.Read(gradientType)
|
||||
|| !buffer.Read(gradientFlags)
|
||||
|| !buffer.Read(gradientStopCount)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Gradient gradient(true);
|
||||
// empty gradient
|
||||
|
||||
gradient.SetType((gradient_type)gradientType);
|
||||
// TODO: support more stuff with flags
|
||||
// ("inherits transformation" and so on)
|
||||
if (gradientFlags & GRADIENT_FLAG_TRANSFORM) {
|
||||
if (!_ReadTransformable(buffer, &gradient))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool alpha = !(gradientFlags & GRADIENT_FLAG_NO_ALPHA);
|
||||
|
||||
for (int32 i = 0; i < gradientStopCount; i++) {
|
||||
uint8 stopOffset;
|
||||
rgb_color color;
|
||||
|
||||
if (!buffer.Read(stopOffset))
|
||||
return NULL;
|
||||
|
||||
if (alpha) {
|
||||
if (!buffer.Read((uint32&)color))
|
||||
return NULL;
|
||||
} else {
|
||||
color.alpha = 255;
|
||||
if (!buffer.Read(color.red)
|
||||
|| !buffer.Read(color.green)
|
||||
|| !buffer.Read(color.blue)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
gradient.AddColor(color, stopOffset / 255.0);
|
||||
}
|
||||
|
||||
style->SetGradient(&gradient);
|
||||
|
||||
styleDeleter.Detach();
|
||||
return style;
|
||||
}
|
||||
|
||||
// _ParseStyles
|
||||
status_t
|
||||
FlatIconImporter::_ParseStyles(LittleEndianBuffer& buffer,
|
||||
StyleContainer* styles)
|
||||
{
|
||||
uint8 styleCount;
|
||||
if (!buffer.Read(styleCount))
|
||||
return B_ERROR;
|
||||
|
||||
for (int32 i = 0; i < styleCount; i++) {
|
||||
uint8 styleType;
|
||||
if (!buffer.Read(styleType))
|
||||
return B_ERROR;
|
||||
Style* style = NULL;
|
||||
if (styleType == TAG_STYLE_SOLID_COLOR) {
|
||||
// solid color
|
||||
style = _ReadColorStyle(buffer, true);
|
||||
if (!style)
|
||||
return B_NO_MEMORY;
|
||||
} else if (styleType == TAG_STYLE_SOLID_COLOR_NO_ALPHA) {
|
||||
// solid color without alpha
|
||||
style = _ReadColorStyle(buffer, false);
|
||||
if (!style)
|
||||
return B_NO_MEMORY;
|
||||
} else if (styleType == TAG_STYLE_GRADIENT) {
|
||||
// gradient
|
||||
style = _ReadGradientStyle(buffer);
|
||||
if (!style)
|
||||
return B_NO_MEMORY;
|
||||
} else {
|
||||
// unkown style type, skip tag
|
||||
uint16 tagLength;
|
||||
if (!buffer.Read(tagLength))
|
||||
return B_ERROR;
|
||||
buffer.Skip(tagLength);
|
||||
continue;
|
||||
}
|
||||
// add style if we were able to read one
|
||||
if (style && !styles->AddStyle(style)) {
|
||||
delete style;
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// read_path_no_curves
|
||||
static bool
|
||||
read_path_no_curves(LittleEndianBuffer& buffer, VectorPath* path,
|
||||
uint8 pointCount)
|
||||
{
|
||||
for (uint32 p = 0; p < pointCount; p++) {
|
||||
BPoint point;
|
||||
if (!read_coord(buffer, point.x)
|
||||
|| !read_coord(buffer, point.y))
|
||||
return false;
|
||||
|
||||
if (!path->AddPoint(point))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// read_path_curves
|
||||
static bool
|
||||
read_path_curves(LittleEndianBuffer& buffer, VectorPath* path,
|
||||
uint8 pointCount)
|
||||
{
|
||||
for (uint32 p = 0; p < pointCount; p++) {
|
||||
BPoint point;
|
||||
if (!read_coord(buffer, point.x)
|
||||
|| !read_coord(buffer, point.y))
|
||||
return false;
|
||||
|
||||
BPoint pointIn;
|
||||
if (!read_coord(buffer, pointIn.x)
|
||||
|| !read_coord(buffer, pointIn.y))
|
||||
return false;
|
||||
|
||||
BPoint pointOut;
|
||||
if (!read_coord(buffer, pointOut.x)
|
||||
|| !read_coord(buffer, pointOut.y))
|
||||
return false;
|
||||
|
||||
if (!path->AddPoint(point, pointIn, pointOut, false))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// read_path_with_commands
|
||||
static bool
|
||||
read_path_with_commands(LittleEndianBuffer& buffer, VectorPath* path,
|
||||
uint8 pointCount)
|
||||
{
|
||||
PathCommandQueue queue;
|
||||
return queue.Read(buffer, path, pointCount);
|
||||
}
|
||||
|
||||
|
||||
// _ParsePaths
|
||||
status_t
|
||||
FlatIconImporter::_ParsePaths(LittleEndianBuffer& buffer,
|
||||
PathContainer* paths)
|
||||
{
|
||||
uint8 pathCount;
|
||||
if (!buffer.Read(pathCount))
|
||||
return B_ERROR;
|
||||
|
||||
for (int32 i = 0; i < pathCount; i++) {
|
||||
uint8 pathFlags;
|
||||
uint8 pointCount;
|
||||
if (!buffer.Read(pathFlags) || !buffer.Read(pointCount))
|
||||
return B_ERROR;
|
||||
|
||||
VectorPath* path = new (nothrow) VectorPath();
|
||||
if (!path)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// chose path reading strategy depending on path flags
|
||||
bool error = false;
|
||||
if (pathFlags & PATH_FLAGS_NO_CURVES) {
|
||||
if (!read_path_no_curves(buffer, path, pointCount))
|
||||
error = true;
|
||||
} else if (pathFlags & PATH_FLAGS_USES_COMMANDS) {
|
||||
if (!read_path_with_commands(buffer, path, pointCount))
|
||||
error = true;
|
||||
} else {
|
||||
if (!read_path_curves(buffer, path, pointCount))
|
||||
error = true;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
delete path;
|
||||
return B_ERROR;
|
||||
}
|
||||
// post process path to clean it up
|
||||
path->CleanUp();
|
||||
if (pathFlags & PATH_FLAGS_CLOSED)
|
||||
path->SetClosed(true);
|
||||
// add path to container
|
||||
if (!paths->AddPath(path)) {
|
||||
delete path;
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// _ReadTransformer
|
||||
static Transformer*
|
||||
_ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source)
|
||||
{
|
||||
uint8 transformerType;
|
||||
if (!buffer.Read(transformerType))
|
||||
return NULL;
|
||||
|
||||
switch (transformerType) {
|
||||
case TAG_TRANSFORMER_AFFINE: {
|
||||
AffineTransformer* affine
|
||||
= new (nothrow) AffineTransformer(source);
|
||||
if (!affine)
|
||||
return NULL;
|
||||
double matrix[6];
|
||||
for (int32 i = 0; i < 6; i++) {
|
||||
float value;
|
||||
if (!buffer.Read(value)) {
|
||||
delete affine;
|
||||
return NULL;
|
||||
}
|
||||
matrix[i] = value;
|
||||
}
|
||||
affine->load_from(matrix);
|
||||
return affine;
|
||||
}
|
||||
case TAG_TRANSFORMER_CONTOUR: {
|
||||
ContourTransformer* contour
|
||||
= new (nothrow) ContourTransformer(source);
|
||||
uint8 width;
|
||||
uint8 lineJoin;
|
||||
uint8 miterLimit;
|
||||
if (!contour
|
||||
|| !buffer.Read(width)
|
||||
|| !buffer.Read(lineJoin)
|
||||
|| !buffer.Read(miterLimit)) {
|
||||
delete contour;
|
||||
return NULL;
|
||||
}
|
||||
contour->width(width - 128.0);
|
||||
contour->line_join((agg::line_join_e)lineJoin);
|
||||
contour->miter_limit(miterLimit);
|
||||
return contour;
|
||||
}
|
||||
case TAG_TRANSFORMER_PERSPECTIVE: {
|
||||
PerspectiveTransformer* perspective
|
||||
= new (nothrow) PerspectiveTransformer(source);
|
||||
// TODO: upgrade AGG to be able to support storage of
|
||||
// trans_perspective
|
||||
return perspective;
|
||||
}
|
||||
case TAG_TRANSFORMER_STROKE: {
|
||||
StrokeTransformer* stroke
|
||||
= new (nothrow) StrokeTransformer(source);
|
||||
uint8 width;
|
||||
uint8 lineJoin;
|
||||
uint8 lineCap;
|
||||
uint8 miterLimit;
|
||||
// uint8 shorten;
|
||||
if (!stroke
|
||||
|| !buffer.Read(width)
|
||||
|| !buffer.Read(lineJoin)
|
||||
|| !buffer.Read(lineCap)
|
||||
|| !buffer.Read(miterLimit)) {
|
||||
delete stroke;
|
||||
return NULL;
|
||||
}
|
||||
stroke->width(width - 128.0);
|
||||
stroke->line_join((agg::line_join_e)lineJoin);
|
||||
stroke->line_cap((agg::line_cap_e)lineCap);
|
||||
stroke->miter_limit(miterLimit);
|
||||
return stroke;
|
||||
}
|
||||
default: {
|
||||
// unkown transformer, skip tag
|
||||
uint16 tagLength;
|
||||
if (!buffer.Read(tagLength))
|
||||
return NULL;
|
||||
buffer.Skip(tagLength);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _ReadPathSourceShape
|
||||
static Shape*
|
||||
_ReadPathSourceShape(LittleEndianBuffer& buffer,
|
||||
StyleContainer* styles, PathContainer* paths)
|
||||
{
|
||||
// find out which style this shape uses
|
||||
uint8 styleIndex;
|
||||
uint8 pathCount;
|
||||
if (!buffer.Read(styleIndex) || !buffer.Read(pathCount))
|
||||
return NULL;
|
||||
|
||||
Style* style = styles->StyleAt(styleIndex);
|
||||
if (!style) {
|
||||
printf("_ReadPathSourceShape() - "
|
||||
"shape references non-existing style %d\n", styleIndex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// create the shape
|
||||
Shape* shape = new (nothrow) Shape(style);
|
||||
ObjectDeleter<Shape> shapeDeleter(shape);
|
||||
|
||||
if (!shape || shape->InitCheck() < B_OK)
|
||||
return NULL;
|
||||
|
||||
// find out which paths this shape uses
|
||||
for (uint32 i = 0; i < pathCount; i++) {
|
||||
uint8 pathIndex;
|
||||
if (!buffer.Read(pathIndex))
|
||||
return NULL;
|
||||
|
||||
VectorPath* path = paths->PathAt(pathIndex);
|
||||
if (!path) {
|
||||
printf("_ReadPathSourceShape() - "
|
||||
"shape references non-existing path %d\n", pathIndex);
|
||||
continue;
|
||||
}
|
||||
shape->Paths()->AddPath(path);
|
||||
}
|
||||
|
||||
// shape flags
|
||||
uint8 shapeFlags;
|
||||
if (!buffer.Read(shapeFlags))
|
||||
return NULL;
|
||||
|
||||
shape->SetHinting(shapeFlags & SHAPE_FLAG_HINTING);
|
||||
|
||||
if (shapeFlags & SHAPE_FLAG_TRANSFORM) {
|
||||
// transformation
|
||||
if (!_ReadTransformable(buffer, shape))
|
||||
return NULL;
|
||||
} else if (shapeFlags & SHAPE_FLAG_TRANSLATION) {
|
||||
// translation
|
||||
if (!_ReadTranslation(buffer, shape))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (shapeFlags & SHAPE_FLAG_LOD_SCALE) {
|
||||
// min max visibility scale
|
||||
uint8 minScale;
|
||||
uint8 maxScale;
|
||||
if (!buffer.Read(minScale) || !buffer.Read(maxScale))
|
||||
return NULL;
|
||||
shape->SetMinVisibilityScale((float)minScale);
|
||||
shape->SetMaxVisibilityScale((float)maxScale);
|
||||
}
|
||||
|
||||
// transformers
|
||||
if (shapeFlags & SHAPE_FLAG_HAS_TRANSFORMERS) {
|
||||
uint8 transformerCount;
|
||||
if (!buffer.Read(transformerCount))
|
||||
return NULL;
|
||||
for (uint32 i = 0; i < transformerCount; i++) {
|
||||
Transformer* transformer
|
||||
= _ReadTransformer(buffer, shape->VertexSource());
|
||||
if (transformer && !shape->AddTransformer(transformer)) {
|
||||
delete transformer;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shapeDeleter.Detach();
|
||||
return shape;
|
||||
}
|
||||
|
||||
// _ParseShapes
|
||||
status_t
|
||||
FlatIconImporter::_ParseShapes(LittleEndianBuffer& buffer,
|
||||
StyleContainer* styles,
|
||||
PathContainer* paths,
|
||||
ShapeContainer* shapes)
|
||||
{
|
||||
uint8 shapeCount;
|
||||
if (!buffer.Read(shapeCount))
|
||||
return B_ERROR;
|
||||
|
||||
for (uint32 i = 0; i < shapeCount; i++) {
|
||||
uint8 shapeType;
|
||||
if (!buffer.Read(shapeType))
|
||||
return B_ERROR;
|
||||
Shape* shape = NULL;
|
||||
if (shapeType == TAG_SHAPE_PATH_SOURCE) {
|
||||
// path source shape
|
||||
shape = _ReadPathSourceShape(buffer, styles, paths);
|
||||
if (!shape)
|
||||
return B_NO_MEMORY;
|
||||
} else {
|
||||
// unkown shape type, skip tag
|
||||
uint16 tagLength;
|
||||
if (!buffer.Read(tagLength))
|
||||
return B_ERROR;
|
||||
buffer.Skip(tagLength);
|
||||
continue;
|
||||
}
|
||||
// add shape if we were able to read one
|
||||
if (shape && !shapes->AddShape(shape)) {
|
||||
delete shape;
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef FLAT_ICON_IMPORTER_H
|
||||
#define FLAT_ICON_IMPORTER_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class BMessage;
|
||||
class BPositionIO;
|
||||
class Icon;
|
||||
class LittleEndianBuffer;
|
||||
class PathContainer;
|
||||
class ShapeContainer;
|
||||
class StyleContainer;
|
||||
|
||||
class FlatIconImporter {
|
||||
public:
|
||||
FlatIconImporter();
|
||||
virtual ~FlatIconImporter();
|
||||
|
||||
// Importer interface (Importer base not yet written)
|
||||
virtual status_t Import(Icon* icon,
|
||||
BPositionIO* stream);
|
||||
|
||||
// FlatIconImporter
|
||||
status_t Import(Icon* icon,
|
||||
uint8* buffer, size_t size);
|
||||
|
||||
private:
|
||||
status_t _ParseSections(LittleEndianBuffer& buffer,
|
||||
Icon* icon);
|
||||
|
||||
status_t _ParseStyles(LittleEndianBuffer& buffer,
|
||||
StyleContainer* styles);
|
||||
status_t _ParsePaths(LittleEndianBuffer& buffer,
|
||||
PathContainer* paths);
|
||||
status_t _ParseShapes(LittleEndianBuffer& buffer,
|
||||
StyleContainer* styles,
|
||||
PathContainer* paths,
|
||||
ShapeContainer* shapes);
|
||||
};
|
||||
|
||||
#endif // FLAT_ICON_IMPORTER_H
|
||||
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "LittleEndianBuffer.h"
|
||||
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ByteOrder.h>
|
||||
|
||||
#define CHUNK_SIZE 256
|
||||
|
||||
// constructor
|
||||
LittleEndianBuffer::LittleEndianBuffer()
|
||||
: fBuffer((uint8*)malloc(CHUNK_SIZE)),
|
||||
fHandle(fBuffer),
|
||||
fBufferEnd(fBuffer + CHUNK_SIZE),
|
||||
fSize(CHUNK_SIZE),
|
||||
fOwnsBuffer(true)
|
||||
{
|
||||
}
|
||||
|
||||
// constructor
|
||||
LittleEndianBuffer::LittleEndianBuffer(size_t size)
|
||||
: fBuffer((uint8*)malloc(size)),
|
||||
fHandle(fBuffer),
|
||||
fBufferEnd(fBuffer + size),
|
||||
fSize(size),
|
||||
fOwnsBuffer(true)
|
||||
{
|
||||
}
|
||||
|
||||
// constructor
|
||||
LittleEndianBuffer::LittleEndianBuffer(uint8* buffer, size_t size)
|
||||
: fBuffer(buffer),
|
||||
fHandle(fBuffer),
|
||||
fBufferEnd(fBuffer + size),
|
||||
fSize(size),
|
||||
fOwnsBuffer(false)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
LittleEndianBuffer::~LittleEndianBuffer()
|
||||
{
|
||||
if (fOwnsBuffer)
|
||||
free(fBuffer);
|
||||
}
|
||||
|
||||
// Write 8
|
||||
bool
|
||||
LittleEndianBuffer::Write(uint8 value)
|
||||
{
|
||||
if (fHandle == fBufferEnd)
|
||||
_SetSize(fSize + CHUNK_SIZE);
|
||||
|
||||
if (!fBuffer)
|
||||
return false;
|
||||
|
||||
*fHandle = value;
|
||||
fHandle++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write 16
|
||||
bool
|
||||
LittleEndianBuffer::Write(uint16 value)
|
||||
{
|
||||
if ((fHandle + 1) >= fBufferEnd)
|
||||
_SetSize(fSize + CHUNK_SIZE);
|
||||
|
||||
if (!fBuffer)
|
||||
return false;
|
||||
|
||||
*(uint16*)fHandle = B_HOST_TO_LENDIAN_INT16(value);
|
||||
fHandle += 2;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write 32
|
||||
bool
|
||||
LittleEndianBuffer::Write(uint32 value)
|
||||
{
|
||||
if ((fHandle + 3) >= fBufferEnd)
|
||||
_SetSize(fSize + CHUNK_SIZE);
|
||||
|
||||
if (!fBuffer)
|
||||
return false;
|
||||
|
||||
*(uint32*)fHandle = B_HOST_TO_LENDIAN_INT32(value);
|
||||
fHandle += 4;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write double
|
||||
bool
|
||||
LittleEndianBuffer::Write(float value)
|
||||
{
|
||||
if ((fHandle + sizeof(float) - 1) >= fBufferEnd)
|
||||
_SetSize(fSize + CHUNK_SIZE);
|
||||
|
||||
if (!fBuffer)
|
||||
return false;
|
||||
|
||||
*(float*)fHandle = B_HOST_TO_LENDIAN_FLOAT(value);
|
||||
fHandle += sizeof(float);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write double
|
||||
bool
|
||||
LittleEndianBuffer::Write(double value)
|
||||
{
|
||||
if ((fHandle + sizeof(double) - 1) >= fBufferEnd)
|
||||
_SetSize(fSize + CHUNK_SIZE);
|
||||
|
||||
if (!fBuffer)
|
||||
return false;
|
||||
|
||||
*(double*)fHandle = B_HOST_TO_LENDIAN_DOUBLE(value);
|
||||
fHandle += sizeof(double);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write LittleEndianBuffer
|
||||
bool
|
||||
LittleEndianBuffer::Write(const LittleEndianBuffer& other)
|
||||
{
|
||||
return Write(other.Buffer(), other.SizeUsed());
|
||||
}
|
||||
|
||||
// Write buffer
|
||||
bool
|
||||
LittleEndianBuffer::Write(const uint8* buffer, size_t bytes)
|
||||
{
|
||||
if (bytes == 0)
|
||||
return true;
|
||||
|
||||
// figure out needed size and suitable new size
|
||||
size_t neededSize = SizeUsed() + bytes;
|
||||
size_t newSize = fSize;
|
||||
while (newSize < neededSize)
|
||||
newSize += CHUNK_SIZE;
|
||||
|
||||
// resize if necessary
|
||||
if (newSize > fSize)
|
||||
_SetSize(newSize);
|
||||
|
||||
if (!fBuffer)
|
||||
return false;
|
||||
|
||||
// paste buffer
|
||||
memcpy(fHandle, buffer, bytes);
|
||||
fHandle += bytes;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// Read 8
|
||||
bool
|
||||
LittleEndianBuffer::Read(uint8& value)
|
||||
{
|
||||
if (fHandle >= fBufferEnd)
|
||||
return false;
|
||||
|
||||
value = *fHandle++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read 16
|
||||
bool
|
||||
LittleEndianBuffer::Read(uint16& value)
|
||||
{
|
||||
if ((fHandle + 1) >= fBufferEnd)
|
||||
return false;
|
||||
|
||||
value = B_LENDIAN_TO_HOST_INT16(*(uint16*)fHandle);
|
||||
fHandle += 2;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read 32
|
||||
bool
|
||||
LittleEndianBuffer::Read(uint32& value)
|
||||
{
|
||||
if ((fHandle + 3) >= fBufferEnd)
|
||||
return false;
|
||||
|
||||
value = B_LENDIAN_TO_HOST_INT32(*(uint32*)fHandle);
|
||||
fHandle += 4;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read float
|
||||
bool
|
||||
LittleEndianBuffer::Read(float& value)
|
||||
{
|
||||
if ((fHandle + sizeof(float) - 1) >= fBufferEnd)
|
||||
return false;
|
||||
|
||||
value = B_LENDIAN_TO_HOST_FLOAT(*(float*)fHandle);
|
||||
fHandle += sizeof(float);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read double
|
||||
bool
|
||||
LittleEndianBuffer::Read(double& value)
|
||||
{
|
||||
if ((fHandle + sizeof(double) - 1) >= fBufferEnd)
|
||||
return false;
|
||||
|
||||
value = B_LENDIAN_TO_HOST_DOUBLE(*(double*)fHandle);
|
||||
fHandle += sizeof(double);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read LittleEndianBuffer
|
||||
bool
|
||||
LittleEndianBuffer::Read(LittleEndianBuffer& other, size_t bytes)
|
||||
{
|
||||
if ((fHandle + bytes - 1) >= fBufferEnd)
|
||||
return false;
|
||||
|
||||
if (other.Write(fHandle, bytes)) {
|
||||
// reset other handle to beginning of pasted data
|
||||
other.fHandle -= bytes;
|
||||
fHandle += bytes;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// Skip
|
||||
void
|
||||
LittleEndianBuffer::Skip(size_t bytes)
|
||||
{
|
||||
// NOTE: is ment to be used while reading!!
|
||||
// when used while writing, the growing will not work reliably
|
||||
fHandle += bytes;
|
||||
}
|
||||
|
||||
// Reset
|
||||
void
|
||||
LittleEndianBuffer::Reset()
|
||||
{
|
||||
fHandle = fBuffer;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _SetSize
|
||||
void
|
||||
LittleEndianBuffer::_SetSize(size_t size)
|
||||
{
|
||||
if (!fOwnsBuffer) {
|
||||
// prevent user error
|
||||
// (we are in read mode)
|
||||
fBuffer = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
int32 pos = fHandle - fBuffer;
|
||||
fBuffer = (uint8*)realloc((void*)fBuffer, size);
|
||||
fHandle = fBuffer + pos;
|
||||
fBufferEnd = fBuffer + size;
|
||||
fSize = size;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef LITTLE_ENDIAN_BUFFER_H
|
||||
#define LITTLE_ENDIAN_BUFFER_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class LittleEndianBuffer {
|
||||
public:
|
||||
LittleEndianBuffer();
|
||||
LittleEndianBuffer(size_t size);
|
||||
LittleEndianBuffer(uint8* buffer,
|
||||
size_t size);
|
||||
~LittleEndianBuffer();
|
||||
|
||||
bool Write(uint8 value);
|
||||
bool Write(uint16 value);
|
||||
bool Write(uint32 value);
|
||||
bool Write(float value);
|
||||
bool Write(double value);
|
||||
|
||||
bool Write(const LittleEndianBuffer& other);
|
||||
bool Write(const uint8* buffer, size_t bytes);
|
||||
|
||||
bool Read(uint8& value);
|
||||
bool Read(uint16& value);
|
||||
bool Read(uint32& value);
|
||||
bool Read(float& value);
|
||||
bool Read(double& value);
|
||||
bool Read(LittleEndianBuffer& other, size_t bytes);
|
||||
|
||||
void Skip(size_t bytes);
|
||||
|
||||
uint8* Buffer() const
|
||||
{ return fBuffer; }
|
||||
size_t SizeUsed() const
|
||||
{ return fHandle - fBuffer; }
|
||||
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
void _SetSize(size_t size);
|
||||
|
||||
uint8* fBuffer;
|
||||
uint8* fHandle;
|
||||
uint8* fBufferEnd;
|
||||
size_t fSize;
|
||||
bool fOwnsBuffer;
|
||||
};
|
||||
|
||||
#endif // LITTLE_ENDIAN_BUFFER_H
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "PathCommandQueue.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Point.h>
|
||||
|
||||
#include "FlatIconFormat.h"
|
||||
#include "VectorPath.h"
|
||||
|
||||
// constructor
|
||||
PathCommandQueue::PathCommandQueue()
|
||||
: fCommandBuffer(),
|
||||
fPointBuffer(),
|
||||
|
||||
fCommandByte(0),
|
||||
fCommandPos(0),
|
||||
|
||||
fCommandCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
PathCommandQueue::~PathCommandQueue()
|
||||
{
|
||||
}
|
||||
|
||||
// Write
|
||||
bool
|
||||
PathCommandQueue::Write(LittleEndianBuffer& buffer,
|
||||
const VectorPath* path, uint8 pointCount)
|
||||
{
|
||||
// reset
|
||||
fCommandCount = 0;
|
||||
fCommandByte = 0;
|
||||
fCommandPos = 0;
|
||||
fCommandBuffer.Reset();
|
||||
fPointBuffer.Reset();
|
||||
|
||||
BPoint last(B_ORIGIN);
|
||||
|
||||
for (uint32 p = 0; p < pointCount; p++) {
|
||||
BPoint point;
|
||||
BPoint pointIn;
|
||||
BPoint pointOut;
|
||||
if (!path->GetPointsAt(p, point, pointIn, pointOut))
|
||||
return false;
|
||||
|
||||
if (point == pointIn && point == pointOut) {
|
||||
// single point is sufficient
|
||||
if (point.x == last.x) {
|
||||
// vertical line
|
||||
if (!_AppendVLine(point.y))
|
||||
return false;
|
||||
} else if (point.y == last.y) {
|
||||
// horizontal line
|
||||
if (!_AppendHLine(point.x))
|
||||
return false;
|
||||
} else {
|
||||
// line
|
||||
if (!_AppendLine(point))
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// needing to write all three points
|
||||
if (!_AppendCurve(point, pointIn, pointOut))
|
||||
return false;
|
||||
}
|
||||
|
||||
last = point;
|
||||
}
|
||||
|
||||
if (fCommandPos > 0) {
|
||||
// the last couple commands have not been written
|
||||
if (!fCommandBuffer.Write(fCommandByte))
|
||||
return false;
|
||||
}
|
||||
|
||||
return buffer.Write(fCommandBuffer) && buffer.Write(fPointBuffer);
|
||||
}
|
||||
|
||||
// Read
|
||||
bool
|
||||
PathCommandQueue::Read(LittleEndianBuffer& buffer,
|
||||
VectorPath* path, uint8 pointCount)
|
||||
{
|
||||
// reset
|
||||
fCommandCount = 0;
|
||||
fCommandByte = 0;
|
||||
fCommandPos = 0;
|
||||
|
||||
fCommandBuffer.Reset();
|
||||
|
||||
// NOTE: fPointBuffer is not used for reading
|
||||
// we read the command buffer and then use the
|
||||
// buffer directly for the coords
|
||||
|
||||
// read command buffer
|
||||
uint8 commandBufferSize = (pointCount + 3) / 4;
|
||||
if (!buffer.Read(fCommandBuffer, commandBufferSize))
|
||||
return false;
|
||||
|
||||
BPoint last(B_ORIGIN);
|
||||
for (uint32 p = 0; p < pointCount; p++) {
|
||||
|
||||
uint8 command;
|
||||
if (!_ReadCommand(command))
|
||||
return false;
|
||||
|
||||
BPoint point;
|
||||
BPoint pointIn;
|
||||
BPoint pointOut;
|
||||
|
||||
switch (command) {
|
||||
case PATH_COMMAND_H_LINE:
|
||||
if (!read_coord(buffer, point.x))
|
||||
return false;
|
||||
point.y = last.y;
|
||||
pointIn = point;
|
||||
pointOut = point;
|
||||
break;
|
||||
case PATH_COMMAND_V_LINE:
|
||||
if (!read_coord(buffer, point.y))
|
||||
return false;
|
||||
point.x = last.x;
|
||||
pointIn = point;
|
||||
pointOut = point;
|
||||
break;
|
||||
case PATH_COMMAND_LINE:
|
||||
if (!read_coord(buffer, point.x)
|
||||
|| !read_coord(buffer, point.y))
|
||||
return false;
|
||||
pointIn = point;
|
||||
pointOut = point;
|
||||
break;
|
||||
case PATH_COMMAND_CURVE:
|
||||
if (!read_coord(buffer, point.x)
|
||||
|| !read_coord(buffer, point.y)
|
||||
|| !read_coord(buffer, pointIn.x)
|
||||
|| !read_coord(buffer, pointIn.y)
|
||||
|| !read_coord(buffer, pointOut.x)
|
||||
|| !read_coord(buffer, pointOut.y))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!path->AddPoint(point, pointIn, pointOut, false))
|
||||
return false;
|
||||
|
||||
last = point;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _AppendHLine
|
||||
bool
|
||||
PathCommandQueue::_AppendHLine(float x)
|
||||
{
|
||||
return _AppendCommand(PATH_COMMAND_H_LINE)
|
||||
&& write_coord(fPointBuffer, x);
|
||||
}
|
||||
|
||||
// _AppendVLine
|
||||
bool
|
||||
PathCommandQueue::_AppendVLine(float y)
|
||||
{
|
||||
return _AppendCommand(PATH_COMMAND_V_LINE)
|
||||
&& write_coord(fPointBuffer, y);
|
||||
}
|
||||
|
||||
// _AppendLine
|
||||
bool
|
||||
PathCommandQueue::_AppendLine(const BPoint& point)
|
||||
{
|
||||
return _AppendCommand(PATH_COMMAND_LINE)
|
||||
&& write_coord(fPointBuffer, point.x)
|
||||
&& write_coord(fPointBuffer, point.y);
|
||||
}
|
||||
|
||||
// _AppendCurve
|
||||
bool
|
||||
PathCommandQueue::_AppendCurve(const BPoint& point,
|
||||
const BPoint& pointIn,
|
||||
const BPoint& pointOut)
|
||||
{
|
||||
return _AppendCommand(PATH_COMMAND_CURVE)
|
||||
&& write_coord(fPointBuffer, point.x)
|
||||
&& write_coord(fPointBuffer, point.y)
|
||||
&& write_coord(fPointBuffer, pointIn.x)
|
||||
&& write_coord(fPointBuffer, pointIn.y)
|
||||
&& write_coord(fPointBuffer, pointOut.x)
|
||||
&& write_coord(fPointBuffer, pointOut.y);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _AppendCommand
|
||||
bool
|
||||
PathCommandQueue::_AppendCommand(uint8 command)
|
||||
{
|
||||
// NOTE: a path command uses 2 bits, so 4 of
|
||||
// them fit into a single byte
|
||||
// after we have appended the fourth command,
|
||||
// the byte is written to fCommandBuffer and
|
||||
// the cycle repeats
|
||||
|
||||
if (fCommandCount == 255) {
|
||||
printf("PathCommandQueue::_AppendCommand() - "
|
||||
"maximum path section count reached\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
fCommandByte |= command << fCommandPos;
|
||||
fCommandPos += 2;
|
||||
fCommandCount++;
|
||||
|
||||
if (fCommandPos == 8) {
|
||||
uint8 commandByte = fCommandByte;
|
||||
fCommandByte = 0;
|
||||
fCommandPos = 0;
|
||||
return fCommandBuffer.Write(commandByte);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// _ReadCommand
|
||||
bool
|
||||
PathCommandQueue::_ReadCommand(uint8& command)
|
||||
{
|
||||
if (fCommandCount == 255) {
|
||||
printf("PathCommandQueue::_NextCommand() - "
|
||||
"maximum path section count reached\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fCommandPos == 0) {
|
||||
// fetch the next four commands from the buffer
|
||||
if (!fCommandBuffer.Read(fCommandByte))
|
||||
return false;
|
||||
}
|
||||
|
||||
command = (fCommandByte >> fCommandPos) & 0x03;
|
||||
fCommandPos += 2;
|
||||
fCommandCount++;
|
||||
|
||||
if (fCommandPos == 8)
|
||||
fCommandPos = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef PATH_COMMAND_QUEUE_H
|
||||
#define PATH_COMMAND_QUEUE_H
|
||||
|
||||
#include "LittleEndianBuffer.h"
|
||||
|
||||
class BPoint;
|
||||
class VectorPath;
|
||||
|
||||
class PathCommandQueue {
|
||||
public:
|
||||
PathCommandQueue();
|
||||
virtual ~PathCommandQueue();
|
||||
|
||||
bool Write(LittleEndianBuffer& buffer,
|
||||
const VectorPath* path,
|
||||
uint8 pointCount);
|
||||
|
||||
bool Read(LittleEndianBuffer& buffer,
|
||||
VectorPath* path,
|
||||
uint8 pointCount);
|
||||
|
||||
private:
|
||||
// writing
|
||||
bool _AppendHLine(float x);
|
||||
bool _AppendVLine(float y);
|
||||
bool _AppendLine(const BPoint& point);
|
||||
bool _AppendCurve(const BPoint& point,
|
||||
const BPoint& pointIn,
|
||||
const BPoint& pointOut);
|
||||
|
||||
bool _AppendCommand(uint8 command);
|
||||
|
||||
// reading
|
||||
bool _ReadCommand(uint8& command);
|
||||
|
||||
LittleEndianBuffer fCommandBuffer;
|
||||
LittleEndianBuffer fPointBuffer;
|
||||
|
||||
uint8 fCommandByte;
|
||||
uint8 fCommandPos;
|
||||
|
||||
uint8 fCommandCount;
|
||||
};
|
||||
|
||||
#endif // PATH_COMMAND_QUEUE_H
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "PathContainer.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include "VectorPath.h"
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
PathContainerListener::PathContainerListener() {}
|
||||
PathContainerListener::~PathContainerListener() {}
|
||||
#endif
|
||||
|
||||
|
||||
// constructor
|
||||
PathContainer::PathContainer(bool ownsPaths)
|
||||
: fPaths(16),
|
||||
fOwnsPaths(ownsPaths),
|
||||
#ifdef ICON_O_MATIC
|
||||
fListeners(2)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
PathContainer::~PathContainer()
|
||||
{
|
||||
#ifdef ICON_O_MATIC
|
||||
int32 count = fListeners.CountItems();
|
||||
if (count > 0) {
|
||||
debugger("~PathContainer() - there are still"
|
||||
"listeners attached\n");
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
_MakeEmpty();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// AddPath
|
||||
bool
|
||||
PathContainer::AddPath(VectorPath* path)
|
||||
{
|
||||
if (!path)
|
||||
return false;
|
||||
|
||||
// prevent adding the same path twice
|
||||
if (HasPath(path))
|
||||
return false;
|
||||
|
||||
if (fPaths.AddItem((void*)path)) {
|
||||
#ifdef ICON_O_MATIC
|
||||
_NotifyPathAdded(path);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
fprintf(stderr, "PathContainer::AddPath() - out of memory!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemovePath
|
||||
bool
|
||||
PathContainer::RemovePath(VectorPath* path)
|
||||
{
|
||||
if (fPaths.RemoveItem((void*)path)) {
|
||||
#ifdef ICON_O_MATIC
|
||||
_NotifyPathRemoved(path);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemovePath
|
||||
VectorPath*
|
||||
PathContainer::RemovePath(int32 index)
|
||||
{
|
||||
VectorPath* path = (VectorPath*)fPaths.RemoveItem(index);
|
||||
#ifdef ICON_O_MATIC
|
||||
if (path) {
|
||||
_NotifyPathRemoved(path);
|
||||
}
|
||||
#endif
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
// MakeEmpty
|
||||
void
|
||||
PathContainer::MakeEmpty()
|
||||
{
|
||||
_MakeEmpty();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// CountPaths
|
||||
int32
|
||||
PathContainer::CountPaths() const
|
||||
{
|
||||
return fPaths.CountItems();
|
||||
}
|
||||
|
||||
// HasPath
|
||||
bool
|
||||
PathContainer::HasPath(VectorPath* path) const
|
||||
{
|
||||
return fPaths.HasItem((void*)path);
|
||||
}
|
||||
|
||||
// IndexOf
|
||||
int32
|
||||
PathContainer::IndexOf(VectorPath* path) const
|
||||
{
|
||||
return fPaths.IndexOf((void*)path);
|
||||
}
|
||||
|
||||
// PathAt
|
||||
VectorPath*
|
||||
PathContainer::PathAt(int32 index) const
|
||||
{
|
||||
return (VectorPath*)fPaths.ItemAt(index);
|
||||
}
|
||||
|
||||
// PathAtFast
|
||||
VectorPath*
|
||||
PathContainer::PathAtFast(int32 index) const
|
||||
{
|
||||
return (VectorPath*)fPaths.ItemAtFast(index);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// AddListener
|
||||
bool
|
||||
PathContainer::AddListener(PathContainerListener* listener)
|
||||
{
|
||||
if (listener && !fListeners.HasItem((void*)listener))
|
||||
return fListeners.AddItem(listener);
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemoveListener
|
||||
bool
|
||||
PathContainer::RemoveListener(PathContainerListener* listener)
|
||||
{
|
||||
return fListeners.RemoveItem(listener);
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _MakeEmpty
|
||||
void
|
||||
PathContainer::_MakeEmpty()
|
||||
{
|
||||
int32 count = CountPaths();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
VectorPath* path = PathAtFast(i);
|
||||
#ifdef ICON_O_MATIC
|
||||
_NotifyPathRemoved(path);
|
||||
if (fOwnsPaths)
|
||||
path->Release();
|
||||
#else
|
||||
if (fOwnsPaths)
|
||||
delete path;
|
||||
#endif
|
||||
}
|
||||
fPaths.MakeEmpty();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// _NotifyPathAdded
|
||||
void
|
||||
PathContainer::_NotifyPathAdded(VectorPath* path) const
|
||||
{
|
||||
BList listeners(fListeners);
|
||||
int32 count = listeners.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
PathContainerListener* listener
|
||||
= (PathContainerListener*)listeners.ItemAtFast(i);
|
||||
listener->PathAdded(path);
|
||||
}
|
||||
}
|
||||
|
||||
// _NotifyPathRemoved
|
||||
void
|
||||
PathContainer::_NotifyPathRemoved(VectorPath* path) const
|
||||
{
|
||||
BList listeners(fListeners);
|
||||
int32 count = listeners.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
PathContainerListener* listener
|
||||
= (PathContainerListener*)listeners.ItemAtFast(i);
|
||||
listener->PathRemoved(path);
|
||||
}
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef PATH_CONTAINER_H
|
||||
#define PATH_CONTAINER_H
|
||||
|
||||
#include <List.h>
|
||||
|
||||
class VectorPath;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
class PathContainerListener {
|
||||
public:
|
||||
PathContainerListener();
|
||||
virtual ~PathContainerListener();
|
||||
|
||||
virtual void PathAdded(VectorPath* path) = 0;
|
||||
virtual void PathRemoved(VectorPath* path) = 0;
|
||||
};
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
class PathContainer {
|
||||
public:
|
||||
PathContainer(bool ownsPaths);
|
||||
virtual ~PathContainer();
|
||||
|
||||
bool AddPath(VectorPath* path);
|
||||
bool RemovePath(VectorPath* path);
|
||||
VectorPath* RemovePath(int32 index);
|
||||
|
||||
void MakeEmpty();
|
||||
|
||||
int32 CountPaths() const;
|
||||
bool HasPath(VectorPath* path) const;
|
||||
int32 IndexOf(VectorPath* path) const;
|
||||
|
||||
VectorPath* PathAt(int32 index) const;
|
||||
VectorPath* PathAtFast(int32 index) const;
|
||||
|
||||
private:
|
||||
void _MakeEmpty();
|
||||
|
||||
BList fPaths;
|
||||
bool fOwnsPaths;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
public:
|
||||
bool AddListener(PathContainerListener* listener);
|
||||
bool RemoveListener(PathContainerListener* listener);
|
||||
|
||||
private:
|
||||
void _NotifyPathAdded(VectorPath* path) const;
|
||||
void _NotifyPathRemoved(VectorPath* path) const;
|
||||
|
||||
BList fListeners;
|
||||
#endif // ICON_O_MATIC
|
||||
};
|
||||
|
||||
#endif // PATH_CONTAINER_H
|
||||
@@ -0,0 +1,676 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Shape.h"
|
||||
|
||||
#include <Message.h>
|
||||
#include <TypeConstants.h>
|
||||
|
||||
#include <new>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "agg_bounding_rect.h"
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
# include "CommonPropertyIDs.h"
|
||||
# include "Property.h"
|
||||
# include "PropertyObject.h"
|
||||
#endif // ICON_O_MATIC
|
||||
#include "Style.h"
|
||||
#include "TransformerFactory.h"
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// constructor
|
||||
ShapeListener::ShapeListener()
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
ShapeListener::~ShapeListener()
|
||||
{
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
Shape::Shape(::Style* style)
|
||||
#ifdef ICON_O_MATIC
|
||||
: IconObject("<shape>"),
|
||||
Transformable(),
|
||||
Observer(),
|
||||
PathContainerListener(),
|
||||
#else
|
||||
: Transformable(),
|
||||
#endif
|
||||
|
||||
fPaths(new (nothrow) PathContainer(false)),
|
||||
fStyle(NULL),
|
||||
|
||||
fPathSource(fPaths),
|
||||
fTransformers(4),
|
||||
fNeedsUpdate(true),
|
||||
|
||||
fLastBounds(0, 0, -1, -1),
|
||||
|
||||
fHinting(false),
|
||||
fMinVisibilityScale(0.0),
|
||||
fMaxVisibilityScale(255.0)
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
, fListeners(8)
|
||||
#endif
|
||||
{
|
||||
SetStyle(style);
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
if (fPaths)
|
||||
fPaths->AddListener(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
// constructor
|
||||
Shape::Shape(const Shape& other)
|
||||
#ifdef ICON_O_MATIC
|
||||
: IconObject(other),
|
||||
Transformable(other),
|
||||
Observer(),
|
||||
PathContainerListener(),
|
||||
#else
|
||||
: Transformable(other),
|
||||
#endif
|
||||
|
||||
fPaths(new (nothrow) PathContainer(false)),
|
||||
fStyle(NULL),
|
||||
|
||||
fPathSource(fPaths),
|
||||
fTransformers(4),
|
||||
fNeedsUpdate(true),
|
||||
|
||||
fLastBounds(0, 0, -1, -1),
|
||||
|
||||
fHinting(other.fHinting),
|
||||
fMinVisibilityScale(other.fMinVisibilityScale),
|
||||
fMaxVisibilityScale(other.fMaxVisibilityScale)
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
, fListeners(8)
|
||||
#endif
|
||||
{
|
||||
SetStyle(other.fStyle);
|
||||
|
||||
if (fPaths) {
|
||||
#ifdef ICON_O_MATIC
|
||||
fPaths->AddListener(this);
|
||||
#endif
|
||||
// copy the path references from
|
||||
// the other shape
|
||||
if (other.fPaths) {
|
||||
int32 count = other.fPaths->CountPaths();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
if (!fPaths->AddPath(other.fPaths->PathAtFast(i)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// clone vertex transformers
|
||||
int32 count = other.CountTransformers();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Transformer* original = other.TransformerAtFast(i);
|
||||
Transformer* cloned = original->Clone(fPathSource);
|
||||
if (!AddTransformer(cloned)) {
|
||||
delete cloned;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// destructor
|
||||
Shape::~Shape()
|
||||
{
|
||||
int32 count = fTransformers.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Transformer* t = (Transformer*)fTransformers.ItemAtFast(i);
|
||||
#ifdef ICON_O_MATIC
|
||||
t->RemoveObserver(this);
|
||||
_NotifyTransformerRemoved(t);
|
||||
#endif
|
||||
delete t;
|
||||
}
|
||||
|
||||
fPaths->MakeEmpty();
|
||||
#ifdef ICON_O_MATIC
|
||||
fPaths->RemoveListener(this);
|
||||
#endif
|
||||
delete fPaths;
|
||||
|
||||
SetStyle(NULL);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
|
||||
// Unarchive
|
||||
status_t
|
||||
Shape::Unarchive(const BMessage* archive)
|
||||
{
|
||||
// IconObject properties
|
||||
status_t ret = IconObject::Unarchive(archive);
|
||||
if (ret < B_OK)
|
||||
return ret;
|
||||
|
||||
// recreate transformers
|
||||
BMessage transformerArchive;
|
||||
for (int32 i = 0;
|
||||
archive->FindMessage("transformer", i,
|
||||
&transformerArchive) == B_OK;
|
||||
i++) {
|
||||
Transformer* transformer
|
||||
= TransformerFactory::TransformerFor(
|
||||
&transformerArchive, VertexSource());
|
||||
if (!transformer || !AddTransformer(transformer)) {
|
||||
delete transformer;
|
||||
}
|
||||
}
|
||||
|
||||
// read transformation
|
||||
int32 size = Transformable::matrix_size;
|
||||
const void* matrix;
|
||||
ssize_t dataSize = size * sizeof(double);
|
||||
ret = archive->FindData("transformation", B_DOUBLE_TYPE,
|
||||
&matrix, &dataSize);
|
||||
if (ret == B_OK && dataSize == (ssize_t)(size * sizeof(double)))
|
||||
LoadFrom((const double*)matrix);
|
||||
|
||||
// hinting
|
||||
if (archive->FindBool("hinting", &fHinting) < B_OK)
|
||||
fHinting = false;
|
||||
|
||||
// min visibility scale
|
||||
if (archive->FindFloat("min visibility scale",
|
||||
&fMinVisibilityScale) < B_OK)
|
||||
fMinVisibilityScale = 0.0;
|
||||
|
||||
// max visibility scale
|
||||
if (archive->FindFloat("max visibility scale",
|
||||
&fMaxVisibilityScale) < B_OK)
|
||||
fMaxVisibilityScale = 255.0;
|
||||
|
||||
if (fMinVisibilityScale < 0.0)
|
||||
fMinVisibilityScale = 0.0;
|
||||
if (fMinVisibilityScale > 255.0)
|
||||
fMinVisibilityScale = 255.0;
|
||||
if (fMaxVisibilityScale < 0.0)
|
||||
fMaxVisibilityScale = 0.0;
|
||||
if (fMaxVisibilityScale > 255.0)
|
||||
fMaxVisibilityScale = 255.0;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Archive
|
||||
status_t
|
||||
Shape::Archive(BMessage* into, bool deep) const
|
||||
{
|
||||
status_t ret = IconObject::Archive(into, deep);
|
||||
|
||||
// transformers
|
||||
if (ret == B_OK) {
|
||||
int32 count = CountTransformers();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Transformer* transformer = TransformerAtFast(i);
|
||||
BMessage transformerArchive;
|
||||
ret = transformer->Archive(&transformerArchive);
|
||||
if (ret == B_OK)
|
||||
ret = into->AddMessage("transformer", &transformerArchive);
|
||||
if (ret < B_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// transformation
|
||||
if (ret == B_OK) {
|
||||
int32 size = Transformable::matrix_size;
|
||||
double matrix[size];
|
||||
StoreTo(matrix);
|
||||
ret = into->AddData("transformation", B_DOUBLE_TYPE,
|
||||
matrix, size * sizeof(double));
|
||||
}
|
||||
|
||||
// hinting
|
||||
if (ret ==B_OK)
|
||||
ret = into->AddBool("hinting", fHinting);
|
||||
|
||||
// min visibility scale
|
||||
if (ret ==B_OK)
|
||||
ret = into->AddFloat("min visibility scale",
|
||||
fMinVisibilityScale);
|
||||
|
||||
// max visibility scale
|
||||
if (ret ==B_OK)
|
||||
ret = into->AddFloat("max visibility scale",
|
||||
fMaxVisibilityScale);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// MakePropertyObject
|
||||
PropertyObject*
|
||||
Shape::MakePropertyObject() const
|
||||
{
|
||||
PropertyObject* object = IconObject::MakePropertyObject();
|
||||
if (!object)
|
||||
return NULL;
|
||||
|
||||
object->AddProperty(new BoolProperty(PROPERTY_HINTING, fHinting));
|
||||
|
||||
object->AddProperty(new FloatProperty(PROPERTY_MIN_VISIBILITY_SCALE,
|
||||
fMinVisibilityScale, 0, 255));
|
||||
|
||||
object->AddProperty(new FloatProperty(PROPERTY_MAX_VISIBILITY_SCALE,
|
||||
fMaxVisibilityScale, 0, 255));
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
// SetToPropertyObject
|
||||
bool
|
||||
Shape::SetToPropertyObject(const PropertyObject* object)
|
||||
{
|
||||
AutoNotificationSuspender _(this);
|
||||
IconObject::SetToPropertyObject(object);
|
||||
|
||||
// hinting
|
||||
SetHinting(object->Value(PROPERTY_HINTING, fHinting));
|
||||
|
||||
// min visibility scale
|
||||
SetMinVisibilityScale(object->Value(PROPERTY_MIN_VISIBILITY_SCALE,
|
||||
fMinVisibilityScale));
|
||||
|
||||
// max visibility scale
|
||||
SetMaxVisibilityScale(object->Value(PROPERTY_MAX_VISIBILITY_SCALE,
|
||||
fMaxVisibilityScale));
|
||||
|
||||
return HasPendingNotifications();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// TransformationChanged
|
||||
void
|
||||
Shape::TransformationChanged()
|
||||
{
|
||||
// TODO: notify appearance change
|
||||
_NotifyRerender();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// ObjectChanged
|
||||
void
|
||||
Shape::ObjectChanged(const Observable* object)
|
||||
{
|
||||
// simply pass on the event for now
|
||||
// (a path, transformer or the style changed,
|
||||
// the shape needs to be re-rendered)
|
||||
_NotifyRerender();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// PathAdded
|
||||
void
|
||||
Shape::PathAdded(VectorPath* path)
|
||||
{
|
||||
path->Acquire();
|
||||
path->AddListener(this);
|
||||
_NotifyRerender();
|
||||
}
|
||||
|
||||
// PathRemoved
|
||||
void
|
||||
Shape::PathRemoved(VectorPath* path)
|
||||
{
|
||||
path->RemoveListener(this);
|
||||
_NotifyRerender();
|
||||
path->Release();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// PointAdded
|
||||
void
|
||||
Shape::PointAdded(int32 index)
|
||||
{
|
||||
_NotifyRerender();
|
||||
}
|
||||
|
||||
// PointRemoved
|
||||
void
|
||||
Shape::PointRemoved(int32 index)
|
||||
{
|
||||
_NotifyRerender();
|
||||
}
|
||||
|
||||
// PointChanged
|
||||
void
|
||||
Shape::PointChanged(int32 index)
|
||||
{
|
||||
_NotifyRerender();
|
||||
}
|
||||
|
||||
// PathChanged
|
||||
void
|
||||
Shape::PathChanged()
|
||||
{
|
||||
_NotifyRerender();
|
||||
}
|
||||
|
||||
// PathClosedChanged
|
||||
void
|
||||
Shape::PathClosedChanged()
|
||||
{
|
||||
_NotifyRerender();
|
||||
}
|
||||
|
||||
// PathReversed
|
||||
void
|
||||
Shape::PathReversed()
|
||||
{
|
||||
_NotifyRerender();
|
||||
}
|
||||
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// InitCheck
|
||||
status_t
|
||||
Shape::InitCheck() const
|
||||
{
|
||||
return fPaths ? B_OK : B_NO_MEMORY;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// SetStyle
|
||||
void
|
||||
Shape::SetStyle(::Style* style)
|
||||
{
|
||||
#ifdef ICON_O_MATIC
|
||||
if (fStyle == style)
|
||||
return;
|
||||
|
||||
if (fStyle) {
|
||||
fStyle->RemoveObserver(this);
|
||||
fStyle->Release();
|
||||
}
|
||||
::Style* oldStyle = fStyle;
|
||||
#else
|
||||
delete fStyle;
|
||||
#endif
|
||||
|
||||
fStyle = style;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
if (fStyle) {
|
||||
fStyle->Acquire();
|
||||
fStyle->AddObserver(this);
|
||||
}
|
||||
|
||||
_NotifyStyleChanged(oldStyle, fStyle);
|
||||
#endif
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// Bounds
|
||||
BRect
|
||||
Shape::Bounds(bool updateLast) const
|
||||
{
|
||||
// TODO: what about sub-paths?!?
|
||||
// the problem is that the path ids are
|
||||
// nowhere stored while converting VectorPath
|
||||
// to agg::path_storage, but it is also unclear
|
||||
// if those would mean anything later on in
|
||||
// the Transformer pipeline
|
||||
uint32 pathID[1];
|
||||
pathID[0] = 0;
|
||||
double left, top, right, bottom;
|
||||
|
||||
::VertexSource& source = const_cast<Shape*>(this)->VertexSource();
|
||||
agg::conv_transform< ::VertexSource, Transformable>
|
||||
transformedSource(source, *this);
|
||||
agg::bounding_rect(transformedSource, pathID, 0, 1,
|
||||
&left, &top, &right, &bottom);
|
||||
|
||||
BRect bounds(left, top, right, bottom);
|
||||
|
||||
if (updateLast)
|
||||
fLastBounds = bounds;
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
// VertexSource
|
||||
::VertexSource&
|
||||
Shape::VertexSource()
|
||||
{
|
||||
::VertexSource* source = &fPathSource;
|
||||
|
||||
int32 count = fTransformers.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Transformer* t = (Transformer*)fTransformers.ItemAtFast(i);
|
||||
t->SetSource(*source);
|
||||
source = t;
|
||||
}
|
||||
|
||||
if (fNeedsUpdate) {
|
||||
fPathSource.Update(source->WantsOpenPaths(),
|
||||
source->ApproximationScale());
|
||||
fNeedsUpdate = false;
|
||||
}
|
||||
|
||||
return *source;
|
||||
}
|
||||
|
||||
// AddTransformer
|
||||
bool
|
||||
Shape::AddTransformer(Transformer* transformer)
|
||||
{
|
||||
return AddTransformer(transformer, CountTransformers());
|
||||
}
|
||||
|
||||
// AddTransformer
|
||||
bool
|
||||
Shape::AddTransformer(Transformer* transformer, int32 index)
|
||||
{
|
||||
if (!transformer)
|
||||
return false;
|
||||
|
||||
if (!fTransformers.AddItem((void*)transformer, index))
|
||||
return false;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
transformer->AddObserver(this);
|
||||
|
||||
_NotifyTransformerAdded(transformer, index);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// RemoveTransformer
|
||||
bool
|
||||
Shape::RemoveTransformer(Transformer* transformer)
|
||||
{
|
||||
if (fTransformers.RemoveItem((void*)transformer)) {
|
||||
#ifdef ICON_O_MATIC
|
||||
transformer->RemoveObserver(this);
|
||||
|
||||
_NotifyTransformerRemoved(transformer);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// CountShapes
|
||||
int32
|
||||
Shape::CountTransformers() const
|
||||
{
|
||||
return fTransformers.CountItems();
|
||||
}
|
||||
|
||||
// HasTransformer
|
||||
bool
|
||||
Shape::HasTransformer(Transformer* transformer) const
|
||||
{
|
||||
return fTransformers.HasItem((void*)transformer);
|
||||
}
|
||||
|
||||
// IndexOf
|
||||
int32
|
||||
Shape::IndexOf(Transformer* transformer) const
|
||||
{
|
||||
return fTransformers.IndexOf((void*)transformer);
|
||||
}
|
||||
|
||||
// TransformerAt
|
||||
Transformer*
|
||||
Shape::TransformerAt(int32 index) const
|
||||
{
|
||||
return (Transformer*)fTransformers.ItemAt(index);
|
||||
}
|
||||
|
||||
// TransformerAtFast
|
||||
Transformer*
|
||||
Shape::TransformerAtFast(int32 index) const
|
||||
{
|
||||
return (Transformer*)fTransformers.ItemAtFast(index);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// SetHinting
|
||||
void
|
||||
Shape::SetHinting(bool hinting)
|
||||
{
|
||||
if (fHinting == hinting)
|
||||
return;
|
||||
|
||||
fHinting = hinting;
|
||||
Notify();
|
||||
}
|
||||
|
||||
// SetMinVisibilityScale
|
||||
void
|
||||
Shape::SetMinVisibilityScale(float scale)
|
||||
{
|
||||
if (fMinVisibilityScale == scale)
|
||||
return;
|
||||
|
||||
fMinVisibilityScale = scale;
|
||||
Notify();
|
||||
}
|
||||
|
||||
// SetMaxVisibilityScale
|
||||
void
|
||||
Shape::SetMaxVisibilityScale(float scale)
|
||||
{
|
||||
if (fMaxVisibilityScale == scale)
|
||||
return;
|
||||
|
||||
fMaxVisibilityScale = scale;
|
||||
Notify();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
|
||||
// AddListener
|
||||
bool
|
||||
Shape::AddListener(ShapeListener* listener)
|
||||
{
|
||||
if (listener && !fListeners.HasItem((void*)listener))
|
||||
return fListeners.AddItem((void*)listener);
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemoveListener
|
||||
bool
|
||||
Shape::RemoveListener(ShapeListener* listener)
|
||||
{
|
||||
return fListeners.RemoveItem((void*)listener);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _NotifyTransformerAdded
|
||||
void
|
||||
Shape::_NotifyTransformerAdded(Transformer* transformer, int32 index) const
|
||||
{
|
||||
BList listeners(fListeners);
|
||||
int32 count = listeners.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
ShapeListener* listener
|
||||
= (ShapeListener*)listeners.ItemAtFast(i);
|
||||
listener->TransformerAdded(transformer, index);
|
||||
}
|
||||
// TODO: merge Observable and ShapeListener interface
|
||||
_NotifyRerender();
|
||||
}
|
||||
|
||||
// _NotifyTransformerRemoved
|
||||
void
|
||||
Shape::_NotifyTransformerRemoved(Transformer* transformer) const
|
||||
{
|
||||
BList listeners(fListeners);
|
||||
int32 count = listeners.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
ShapeListener* listener
|
||||
= (ShapeListener*)listeners.ItemAtFast(i);
|
||||
listener->TransformerRemoved(transformer);
|
||||
}
|
||||
// TODO: merge Observable and ShapeListener interface
|
||||
_NotifyRerender();
|
||||
}
|
||||
|
||||
// _NotifyStyleChanged
|
||||
void
|
||||
Shape::_NotifyStyleChanged(::Style* oldStyle, ::Style* newStyle) const
|
||||
{
|
||||
BList listeners(fListeners);
|
||||
int32 count = listeners.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
ShapeListener* listener
|
||||
= (ShapeListener*)listeners.ItemAtFast(i);
|
||||
listener->StyleChanged(oldStyle, newStyle);
|
||||
}
|
||||
// TODO: merge Observable and ShapeListener interface
|
||||
_NotifyRerender();
|
||||
}
|
||||
|
||||
// _NotifyRerender
|
||||
void
|
||||
Shape::_NotifyRerender() const
|
||||
{
|
||||
fNeedsUpdate = true;
|
||||
Notify();
|
||||
}
|
||||
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef SHAPE_H
|
||||
#define SHAPE_H
|
||||
|
||||
#include <List.h>
|
||||
#include <Rect.h>
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
# include "IconObject.h"
|
||||
# include "Observer.h"
|
||||
#endif
|
||||
#include "PathContainer.h"
|
||||
#include "PathSource.h"
|
||||
#include "Transformable.h"
|
||||
#include "VectorPath.h"
|
||||
|
||||
class Style;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// TODO: merge Observer and ShapeListener interface
|
||||
// ie add "AppearanceChanged(Shape* shape)"
|
||||
class ShapeListener {
|
||||
public:
|
||||
ShapeListener();
|
||||
virtual ~ShapeListener();
|
||||
|
||||
virtual void TransformerAdded(Transformer* t,
|
||||
int32 index) = 0;
|
||||
virtual void TransformerRemoved(Transformer* t) = 0;
|
||||
|
||||
virtual void StyleChanged(::Style* oldStyle,
|
||||
::Style* newStyle) = 0;
|
||||
};
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
class Shape : public IconObject,
|
||||
public Transformable,
|
||||
public Observer, // observing all the paths and the style
|
||||
public PathContainerListener,
|
||||
public PathListener {
|
||||
#else
|
||||
class Shape : public Transformable {
|
||||
#endif
|
||||
|
||||
public:
|
||||
Shape(::Style* style);
|
||||
Shape(const Shape& other);
|
||||
virtual ~Shape();
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// IconObject interface
|
||||
virtual status_t Unarchive(const BMessage* archive);
|
||||
virtual status_t Archive(BMessage* into,
|
||||
bool deep = true) const;
|
||||
|
||||
virtual PropertyObject* MakePropertyObject() const;
|
||||
virtual bool SetToPropertyObject(
|
||||
const PropertyObject* object);
|
||||
|
||||
// Transformable interface
|
||||
virtual void TransformationChanged();
|
||||
|
||||
// Observer interface
|
||||
virtual void ObjectChanged(const Observable* object);
|
||||
|
||||
// PathContainerListener interface
|
||||
virtual void PathAdded(VectorPath* path);
|
||||
virtual void PathRemoved(VectorPath* path);
|
||||
|
||||
// PathListener interface
|
||||
virtual void PointAdded(int32 index);
|
||||
virtual void PointRemoved(int32 index);
|
||||
virtual void PointChanged(int32 index);
|
||||
virtual void PathChanged();
|
||||
virtual void PathClosedChanged();
|
||||
virtual void PathReversed();
|
||||
#else
|
||||
inline void Notify() {}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
// Shape
|
||||
status_t InitCheck() const;
|
||||
|
||||
inline PathContainer* Paths() const
|
||||
{ return fPaths; }
|
||||
|
||||
void SetStyle(::Style* style);
|
||||
inline ::Style* Style() const
|
||||
{ return fStyle; }
|
||||
|
||||
inline BRect LastBounds() const
|
||||
{ return fLastBounds; }
|
||||
BRect Bounds(bool updateLast = false) const;
|
||||
|
||||
::VertexSource& VertexSource();
|
||||
|
||||
bool AddTransformer(Transformer* transformer);
|
||||
bool AddTransformer(Transformer* transformer,
|
||||
int32 index);
|
||||
bool RemoveTransformer(Transformer* transformer);
|
||||
|
||||
int32 CountTransformers() const;
|
||||
|
||||
bool HasTransformer(Transformer* transformer) const;
|
||||
int32 IndexOf(Transformer* transformer) const;
|
||||
|
||||
Transformer* TransformerAt(int32 index) const;
|
||||
Transformer* TransformerAtFast(int32 index) const;
|
||||
|
||||
void SetHinting(bool hinting);
|
||||
bool Hinting() const
|
||||
{ return fHinting; }
|
||||
void SetMinVisibilityScale(float scale);
|
||||
float MinVisibilityScale() const
|
||||
{ return fMinVisibilityScale; }
|
||||
void SetMaxVisibilityScale(float scale);
|
||||
float MaxVisibilityScale() const
|
||||
{ return fMaxVisibilityScale; }
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
bool AddListener(ShapeListener* listener);
|
||||
bool RemoveListener(ShapeListener* listener);
|
||||
|
||||
private:
|
||||
void _NotifyTransformerAdded(Transformer* t,
|
||||
int32 index) const;
|
||||
void _NotifyTransformerRemoved(Transformer* t) const;
|
||||
|
||||
void _NotifyStyleChanged(::Style* oldStyle,
|
||||
::Style* newStyle) const;
|
||||
|
||||
void _NotifyRerender() const;
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
private:
|
||||
PathContainer* fPaths;
|
||||
::Style* fStyle;
|
||||
|
||||
PathSource fPathSource;
|
||||
BList fTransformers;
|
||||
mutable bool fNeedsUpdate;
|
||||
|
||||
mutable BRect fLastBounds;
|
||||
|
||||
bool fHinting;
|
||||
float fMinVisibilityScale;
|
||||
float fMaxVisibilityScale;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
BList fListeners;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // SHAPE_H
|
||||
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "ShapeContainer.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include "Shape.h"
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// constructor
|
||||
ShapeContainerListener::ShapeContainerListener()
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
ShapeContainerListener::~ShapeContainerListener()
|
||||
{
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
|
||||
|
||||
// constructor
|
||||
ShapeContainer::ShapeContainer()
|
||||
: fShapes(16)
|
||||
#ifdef ICON_O_MATIC
|
||||
, fListeners(2)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
ShapeContainer::~ShapeContainer()
|
||||
{
|
||||
#ifdef ICON_O_MATIC
|
||||
int32 count = fListeners.CountItems();
|
||||
if (count > 0) {
|
||||
debugger("~ShapeContainer() - there are still"
|
||||
"listeners attached\n");
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
_MakeEmpty();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// AddShape
|
||||
bool
|
||||
ShapeContainer::AddShape(Shape* shape)
|
||||
{
|
||||
return AddShape(shape, CountShapes());
|
||||
}
|
||||
|
||||
// AddShape
|
||||
bool
|
||||
ShapeContainer::AddShape(Shape* shape, int32 index)
|
||||
{
|
||||
if (!shape)
|
||||
return false;
|
||||
|
||||
// prevent adding the same shape twice
|
||||
if (HasShape(shape))
|
||||
return false;
|
||||
|
||||
if (fShapes.AddItem((void*)shape, index)) {
|
||||
#ifdef ICON_O_MATIC
|
||||
_NotifyShapeAdded(shape, index);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
fprintf(stderr, "ShapeContainer::AddShape() - out of memory!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemoveShape
|
||||
bool
|
||||
ShapeContainer::RemoveShape(Shape* shape)
|
||||
{
|
||||
if (fShapes.RemoveItem((void*)shape)) {
|
||||
#ifdef ICON_O_MATIC
|
||||
_NotifyShapeRemoved(shape);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemoveShape
|
||||
Shape*
|
||||
ShapeContainer::RemoveShape(int32 index)
|
||||
{
|
||||
Shape* shape = (Shape*)fShapes.RemoveItem(index);
|
||||
#ifdef ICON_O_MATIC
|
||||
if (shape) {
|
||||
_NotifyShapeRemoved(shape);
|
||||
}
|
||||
#endif
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
// MakeEmpty
|
||||
void
|
||||
ShapeContainer::MakeEmpty()
|
||||
{
|
||||
_MakeEmpty();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// CountShapes
|
||||
int32
|
||||
ShapeContainer::CountShapes() const
|
||||
{
|
||||
return fShapes.CountItems();
|
||||
}
|
||||
|
||||
// HasShape
|
||||
bool
|
||||
ShapeContainer::HasShape(Shape* shape) const
|
||||
{
|
||||
return fShapes.HasItem((void*)shape);
|
||||
}
|
||||
|
||||
// IndexOf
|
||||
int32
|
||||
ShapeContainer::IndexOf(Shape* shape) const
|
||||
{
|
||||
return fShapes.IndexOf((void*)shape);
|
||||
}
|
||||
|
||||
// ShapeAt
|
||||
Shape*
|
||||
ShapeContainer::ShapeAt(int32 index) const
|
||||
{
|
||||
return (Shape*)fShapes.ItemAt(index);
|
||||
}
|
||||
|
||||
// ShapeAtFast
|
||||
Shape*
|
||||
ShapeContainer::ShapeAtFast(int32 index) const
|
||||
{
|
||||
return (Shape*)fShapes.ItemAtFast(index);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
|
||||
// AddListener
|
||||
bool
|
||||
ShapeContainer::AddListener(ShapeContainerListener* listener)
|
||||
{
|
||||
if (listener && !fListeners.HasItem((void*)listener))
|
||||
return fListeners.AddItem((void*)listener);
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemoveListener
|
||||
bool
|
||||
ShapeContainer::RemoveListener(ShapeContainerListener* listener)
|
||||
{
|
||||
return fListeners.RemoveItem((void*)listener);
|
||||
}
|
||||
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _MakeEmpty
|
||||
void
|
||||
ShapeContainer::_MakeEmpty()
|
||||
{
|
||||
int32 count = CountShapes();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Shape* shape = ShapeAtFast(i);
|
||||
#ifdef ICON_O_MATIC
|
||||
_NotifyShapeRemoved(shape);
|
||||
shape->Release();
|
||||
#else
|
||||
delete shape;
|
||||
#endif
|
||||
}
|
||||
fShapes.MakeEmpty();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
|
||||
// _NotifyShapeAdded
|
||||
void
|
||||
ShapeContainer::_NotifyShapeAdded(Shape* shape, int32 index) const
|
||||
{
|
||||
BList listeners(fListeners);
|
||||
int32 count = listeners.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
ShapeContainerListener* listener
|
||||
= (ShapeContainerListener*)listeners.ItemAtFast(i);
|
||||
listener->ShapeAdded(shape, index);
|
||||
}
|
||||
}
|
||||
|
||||
// _NotifyShapeRemoved
|
||||
void
|
||||
ShapeContainer::_NotifyShapeRemoved(Shape* shape) const
|
||||
{
|
||||
BList listeners(fListeners);
|
||||
int32 count = listeners.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
ShapeContainerListener* listener
|
||||
= (ShapeContainerListener*)listeners.ItemAtFast(i);
|
||||
listener->ShapeRemoved(shape);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ICON_O_MATIC
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef SHAPE_CONTAINER_H
|
||||
#define SHAPE_CONTAINER_H
|
||||
|
||||
#include <List.h>
|
||||
|
||||
class Shape;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
class ShapeContainerListener {
|
||||
public:
|
||||
ShapeContainerListener();
|
||||
virtual ~ShapeContainerListener();
|
||||
|
||||
virtual void ShapeAdded(Shape* shape, int32 index) = 0;
|
||||
virtual void ShapeRemoved(Shape* shape) = 0;
|
||||
};
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
class ShapeContainer {
|
||||
public:
|
||||
ShapeContainer();
|
||||
virtual ~ShapeContainer();
|
||||
|
||||
bool AddShape(Shape* shape);
|
||||
bool AddShape(Shape* shape, int32 index);
|
||||
bool RemoveShape(Shape* shape);
|
||||
Shape* RemoveShape(int32 index);
|
||||
|
||||
void MakeEmpty();
|
||||
|
||||
int32 CountShapes() const;
|
||||
bool HasShape(Shape* shape) const;
|
||||
int32 IndexOf(Shape* shape) const;
|
||||
|
||||
Shape* ShapeAt(int32 index) const;
|
||||
Shape* ShapeAtFast(int32 index) const;
|
||||
|
||||
private:
|
||||
void _MakeEmpty();
|
||||
|
||||
BList fShapes;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
public:
|
||||
bool AddListener(ShapeContainerListener* listener);
|
||||
bool RemoveListener(
|
||||
ShapeContainerListener* listener);
|
||||
|
||||
private:
|
||||
void _NotifyShapeAdded(Shape* shape,
|
||||
int32 index) const;
|
||||
void _NotifyShapeRemoved(Shape* shape) const;
|
||||
|
||||
BList fListeners;
|
||||
#endif // ICON_O_MATIC
|
||||
};
|
||||
|
||||
#endif // SHAPE_CONTAINER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef VECTOR_PATH_H
|
||||
#define VECTOR_PATH_H
|
||||
|
||||
#include <Rect.h>
|
||||
#include <String.h>
|
||||
|
||||
#include <agg_path_storage.h>
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
# include <Archivable.h>
|
||||
# include <List.h>
|
||||
|
||||
# include "IconObject.h"
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
class BBitmap;
|
||||
class BMessage;
|
||||
class BView;
|
||||
|
||||
struct control_point {
|
||||
BPoint point; // actual point on path
|
||||
BPoint point_in; // control point for incomming curve
|
||||
BPoint point_out; // control point for outgoing curve
|
||||
bool connected; // if all 3 points should be on one line
|
||||
};
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
class PathListener {
|
||||
public:
|
||||
PathListener();
|
||||
virtual ~PathListener();
|
||||
|
||||
virtual void PointAdded(int32 index) = 0;
|
||||
virtual void PointRemoved(int32 index) = 0;
|
||||
virtual void PointChanged(int32 index) = 0;
|
||||
virtual void PathChanged() = 0;
|
||||
virtual void PathClosedChanged() = 0;
|
||||
virtual void PathReversed() = 0;
|
||||
};
|
||||
|
||||
class VectorPath : public BArchivable,
|
||||
public IconObject {
|
||||
#else
|
||||
class VectorPath {
|
||||
#endif // ICON_O_MATIC
|
||||
public:
|
||||
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator() {}
|
||||
virtual ~Iterator() {}
|
||||
|
||||
virtual void MoveTo(BPoint point) = 0;
|
||||
virtual void LineTo(BPoint point) = 0;
|
||||
};
|
||||
|
||||
VectorPath();
|
||||
VectorPath(const VectorPath& from);
|
||||
#ifdef ICON_O_MATIC
|
||||
VectorPath(BMessage* archive);
|
||||
#endif
|
||||
virtual ~VectorPath();
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// IconObject
|
||||
virtual status_t Archive(BMessage* into,
|
||||
bool deep = true) const;
|
||||
|
||||
virtual PropertyObject* MakePropertyObject() const;
|
||||
virtual bool SetToPropertyObject(
|
||||
const PropertyObject* object);
|
||||
#else
|
||||
inline void Notify() {}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
// VectorPath
|
||||
VectorPath& operator=(const VectorPath& from);
|
||||
// bool operator==(const VectorPath& frrom) const;
|
||||
|
||||
void MakeEmpty();
|
||||
|
||||
bool AddPoint(BPoint point);
|
||||
bool AddPoint(const BPoint& point,
|
||||
const BPoint& pointIn,
|
||||
const BPoint& pointOut,
|
||||
bool connected);
|
||||
bool AddPoint(BPoint point, int32 index);
|
||||
|
||||
bool RemovePoint(int32 index);
|
||||
|
||||
// modify existing points position
|
||||
bool SetPoint(int32 index, BPoint point);
|
||||
bool SetPoint(int32 index, BPoint point,
|
||||
BPoint pointIn,
|
||||
BPoint pointOut,
|
||||
bool connected);
|
||||
bool SetPointIn(int32 index, BPoint point);
|
||||
bool SetPointOut(int32 index, BPoint point,
|
||||
bool mirrorDist = false);
|
||||
|
||||
bool SetInOutConnected(int32 index, bool connected);
|
||||
|
||||
// query existing points position
|
||||
bool GetPointAt(int32 index, BPoint& point) const;
|
||||
bool GetPointInAt(int32 index, BPoint& point) const;
|
||||
bool GetPointOutAt(int32 index, BPoint& point) const;
|
||||
bool GetPointsAt(int32 index,
|
||||
BPoint& point,
|
||||
BPoint& pointIn,
|
||||
BPoint& pointOut,
|
||||
bool* connected = NULL) const;
|
||||
|
||||
int32 CountPoints() const;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// iterates over curve segments and returns
|
||||
// the distance and index of the point that
|
||||
// started the segment that is closest
|
||||
bool GetDistance(BPoint point,
|
||||
float* distance, int32* index) const;
|
||||
|
||||
// at curve segment indicated by "index", this
|
||||
// function looks for the closest point
|
||||
// directly on the curve and returns a "scale"
|
||||
// that indicates the distance on the curve
|
||||
// between [0..1]
|
||||
bool FindBezierScale(int32 index, BPoint point,
|
||||
double* scale) const;
|
||||
// this function can be used to get a point
|
||||
// directly on the segment indicated by "index"
|
||||
// "scale" is on [0..1] indicating the distance
|
||||
// from the start of the segment to the end
|
||||
bool GetPoint(int32 index, double scale,
|
||||
BPoint& point) const;
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
void SetClosed(bool closed);
|
||||
bool IsClosed() const
|
||||
{ return fClosed; }
|
||||
|
||||
BRect Bounds() const;
|
||||
BRect ControlPointBounds() const;
|
||||
|
||||
void Iterate(Iterator* iterator,
|
||||
float smoothScale = 1.0) const;
|
||||
|
||||
void CleanUp();
|
||||
void Reverse();
|
||||
|
||||
void PrintToStream() const;
|
||||
|
||||
bool GetAGGPathStorage(agg::path_storage& path) const;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
bool AddListener(PathListener* listener);
|
||||
bool RemoveListener(PathListener* listener);
|
||||
int32 CountListeners() const;
|
||||
PathListener* ListenerAtFast(int32 index) const;
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
|
||||
private:
|
||||
BRect _Bounds() const;
|
||||
void _SetPoint(int32 index, BPoint point);
|
||||
void _SetPoint(int32 index,
|
||||
const BPoint& point,
|
||||
const BPoint& pointIn,
|
||||
const BPoint& pointOut,
|
||||
bool connected);
|
||||
bool _SetPointCount(int32 count);
|
||||
|
||||
#ifndef ICON_O_MATIC
|
||||
inline void _NotifyPointAdded(int32 index) const {}
|
||||
inline void _NotifyPointChanged(int32 index) const {}
|
||||
inline void _NotifyPointRemoved(int32 index) const {}
|
||||
inline void _NotifyPathChanged() const {}
|
||||
inline void _NotifyClosedChanged() const {}
|
||||
inline void _NotifyPathReversed() const {}
|
||||
#else
|
||||
void _NotifyPointAdded(int32 index) const;
|
||||
void _NotifyPointChanged(int32 index) const;
|
||||
void _NotifyPointRemoved(int32 index) const;
|
||||
void _NotifyPathChanged() const;
|
||||
void _NotifyClosedChanged() const;
|
||||
void _NotifyPathReversed() const;
|
||||
|
||||
BList fListeners;
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
control_point* fPath;
|
||||
bool fClosed;
|
||||
|
||||
int32 fPointCount;
|
||||
int32 fAllocCount;
|
||||
|
||||
mutable BRect fCachedBounds;
|
||||
};
|
||||
|
||||
#endif // VECTOR_PATH_H
|
||||
|
||||
@@ -0,0 +1,638 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Gradient.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Message.h>
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
# include "support.h"
|
||||
#endif
|
||||
|
||||
// constructor
|
||||
color_step::color_step(const rgb_color c, float o)
|
||||
{
|
||||
color.red = c.red;
|
||||
color.green = c.green;
|
||||
color.blue = c.blue;
|
||||
color.alpha = c.alpha;
|
||||
offset = o;
|
||||
}
|
||||
|
||||
// constructor
|
||||
color_step::color_step(uint8 r, uint8 g, uint8 b, uint8 a, float o)
|
||||
{
|
||||
color.red = r;
|
||||
color.green = g;
|
||||
color.blue = b;
|
||||
color.alpha = a;
|
||||
offset = o;
|
||||
}
|
||||
|
||||
// constructor
|
||||
color_step::color_step(const color_step& other)
|
||||
{
|
||||
color.red = other.color.red;
|
||||
color.green = other.color.green;
|
||||
color.blue = other.color.blue;
|
||||
color.alpha = other.color.alpha;
|
||||
offset = other.offset;
|
||||
}
|
||||
|
||||
// constructor
|
||||
color_step::color_step()
|
||||
{
|
||||
color.red = 0;
|
||||
color.green = 0;
|
||||
color.blue = 0;
|
||||
color.alpha = 255;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
// operator!=
|
||||
bool
|
||||
color_step::operator!=(const color_step& other) const
|
||||
{
|
||||
return color.red != other.color.red ||
|
||||
color.green != other.color.green ||
|
||||
color.blue != other.color.blue ||
|
||||
color.alpha != other.color.alpha ||
|
||||
offset != other.offset;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
Gradient::Gradient(bool empty)
|
||||
#ifdef ICON_O_MATIC
|
||||
: BArchivable(),
|
||||
Observable(),
|
||||
Transformable(),
|
||||
#else
|
||||
: Transformable(),
|
||||
#endif
|
||||
|
||||
fColors(4),
|
||||
fType(GRADIENT_LINEAR),
|
||||
fInterpolation(INTERPOLATION_SMOOTH),
|
||||
fInheritTransformation(true)
|
||||
{
|
||||
if (!empty) {
|
||||
AddColor(color_step(0, 0, 0, 255, 0.0), 0);
|
||||
AddColor(color_step(255, 255, 255, 255, 1.0), 1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// constructor
|
||||
Gradient::Gradient(BMessage* archive)
|
||||
: BArchivable(archive),
|
||||
Observable(),
|
||||
Transformable(),
|
||||
|
||||
fColors(4),
|
||||
fType(GRADIENT_LINEAR),
|
||||
fInterpolation(INTERPOLATION_SMOOTH),
|
||||
fInheritTransformation(true)
|
||||
{
|
||||
if (!archive)
|
||||
return;
|
||||
|
||||
// read transformation
|
||||
int32 size = Transformable::matrix_size;
|
||||
const void* matrix;
|
||||
ssize_t dataSize = size * sizeof(double);
|
||||
if (archive->FindData("transformation", B_DOUBLE_TYPE,
|
||||
&matrix, &dataSize) == B_OK
|
||||
&& dataSize == (ssize_t)(size * sizeof(double)))
|
||||
LoadFrom((const double*)matrix);
|
||||
|
||||
// color steps
|
||||
color_step step;
|
||||
for (int32 i = 0; archive->FindFloat("offset", i, &step.offset) >= B_OK; i++) {
|
||||
if (archive->FindInt32("color", i, (int32*)&step.color) >= B_OK)
|
||||
AddColor(step, i);
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (archive->FindInt32("type", (int32*)&fType) < B_OK)
|
||||
fType = GRADIENT_LINEAR;
|
||||
|
||||
if (archive->FindInt32("interpolation", (int32*)&fInterpolation) < B_OK)
|
||||
fInterpolation = INTERPOLATION_SMOOTH;
|
||||
|
||||
if (archive->FindBool("inherit transformation",
|
||||
&fInheritTransformation) < B_OK)
|
||||
fInheritTransformation = true;
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
// constructor
|
||||
Gradient::Gradient(const Gradient& other)
|
||||
#ifdef ICON_O_MATIC
|
||||
: BArchivable(other),
|
||||
Observable(),
|
||||
Transformable(other),
|
||||
#else
|
||||
: Transformable(other),
|
||||
#endif
|
||||
|
||||
fColors(4),
|
||||
fType(other.fType),
|
||||
fInterpolation(other.fInterpolation),
|
||||
fInheritTransformation(other.fInheritTransformation)
|
||||
{
|
||||
for (int32 i = 0; color_step* step = other.ColorAt(i); i++) {
|
||||
AddColor(*step, i);
|
||||
}
|
||||
}
|
||||
|
||||
// destructor
|
||||
Gradient::~Gradient()
|
||||
{
|
||||
_MakeEmpty();
|
||||
}
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// Archive
|
||||
status_t
|
||||
Gradient::Archive(BMessage* into, bool deep) const
|
||||
{
|
||||
status_t ret = BArchivable::Archive(into, deep);
|
||||
|
||||
// transformation
|
||||
if (ret == B_OK) {
|
||||
int32 size = Transformable::matrix_size;
|
||||
double matrix[size];
|
||||
StoreTo(matrix);
|
||||
ret = into->AddData("transformation", B_DOUBLE_TYPE,
|
||||
matrix, size * sizeof(double));
|
||||
}
|
||||
|
||||
// color steps
|
||||
if (ret >= B_OK) {
|
||||
for (int32 i = 0; color_step* step = ColorAt(i); i++) {
|
||||
ret = into->AddInt32("color", (const uint32&)step->color);
|
||||
if (ret < B_OK)
|
||||
break;
|
||||
ret = into->AddFloat("offset", step->offset);
|
||||
if (ret < B_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
// gradient and interpolation type
|
||||
if (ret >= B_OK)
|
||||
ret = into->AddInt32("type", (int32)fType);
|
||||
if (ret >= B_OK)
|
||||
ret = into->AddInt32("interpolation", (int32)fInterpolation);
|
||||
if (ret >= B_OK)
|
||||
ret = into->AddBool("inherit transformation", fInheritTransformation);
|
||||
|
||||
// finish off
|
||||
if (ret >= B_OK)
|
||||
ret = into->AddString("class", "Gradient");
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// operator=
|
||||
Gradient&
|
||||
Gradient::operator=(const Gradient& other)
|
||||
{
|
||||
#ifdef ICON_O_MATIC
|
||||
AutoNotificationSuspender _(this);
|
||||
#endif
|
||||
|
||||
SetTransform(other);
|
||||
SetColors(other);
|
||||
SetType(other.fType);
|
||||
SetInterpolation(other.fInterpolation);
|
||||
SetInheritTransformation(other.fInheritTransformation);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// operator==
|
||||
bool
|
||||
Gradient::operator==(const Gradient& other) const
|
||||
{
|
||||
if (Transformable::operator==(other)) {
|
||||
int32 count = CountColors();
|
||||
if (count == other.CountColors() &&
|
||||
fType == other.fType &&
|
||||
fInterpolation == other.fInterpolation &&
|
||||
fInheritTransformation == other.fInheritTransformation) {
|
||||
|
||||
bool equal = true;
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
color_step* ourStep = ColorAtFast(i);
|
||||
color_step* otherStep = other.ColorAtFast(i);
|
||||
if (*ourStep != *otherStep) {
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return equal;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// operator!=
|
||||
bool
|
||||
Gradient::operator!=(const Gradient& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
// SetColors
|
||||
void
|
||||
Gradient::SetColors(const Gradient& other)
|
||||
{
|
||||
#ifdef ICON_O_MATIC
|
||||
AutoNotificationSuspender _(this);
|
||||
#endif
|
||||
|
||||
_MakeEmpty();
|
||||
for (int32 i = 0; color_step* step = other.ColorAt(i); i++)
|
||||
AddColor(*step, i);
|
||||
|
||||
Notify();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// AddColor
|
||||
int32
|
||||
Gradient::AddColor(const rgb_color& color, float offset)
|
||||
{
|
||||
// find the correct index (sorted by offset)
|
||||
color_step* step = new color_step(color, offset);
|
||||
int32 index = 0;
|
||||
int32 count = CountColors();
|
||||
for (; index < count; index++) {
|
||||
color_step* s = ColorAtFast(index);
|
||||
if (s->offset > step->offset)
|
||||
break;
|
||||
}
|
||||
if (!fColors.AddItem((void*)step, index)) {
|
||||
delete step;
|
||||
return -1;
|
||||
}
|
||||
Notify();
|
||||
return index;
|
||||
}
|
||||
|
||||
// AddColor
|
||||
bool
|
||||
Gradient::AddColor(const color_step& color, int32 index)
|
||||
{
|
||||
color_step* step = new color_step(color);
|
||||
if (!fColors.AddItem((void*)step, index)) {
|
||||
delete step;
|
||||
return false;
|
||||
}
|
||||
Notify();
|
||||
return true;
|
||||
}
|
||||
|
||||
// RemoveColor
|
||||
bool
|
||||
Gradient::RemoveColor(int32 index)
|
||||
{
|
||||
color_step* step = (color_step*)fColors.RemoveItem(index);
|
||||
if (!step) {
|
||||
return false;
|
||||
}
|
||||
delete step;
|
||||
Notify();
|
||||
return true;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// SetColor
|
||||
bool
|
||||
Gradient::SetColor(int32 index, const color_step& color)
|
||||
{
|
||||
if (color_step* step = ColorAt(index)) {
|
||||
if (*step != color) {
|
||||
step->color = color.color;
|
||||
step->offset = color.offset;
|
||||
Notify();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// SetColor
|
||||
bool
|
||||
Gradient::SetColor(int32 index, const rgb_color& color)
|
||||
{
|
||||
if (color_step* step = ColorAt(index)) {
|
||||
if ((uint32&)step->color != (uint32&)color) {
|
||||
step->color = color;
|
||||
Notify();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// SetOffset
|
||||
bool
|
||||
Gradient::SetOffset(int32 index, float offset)
|
||||
{
|
||||
color_step* step = ColorAt(index);
|
||||
if (step && step->offset != offset) {
|
||||
step->offset = offset;
|
||||
Notify();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// CountColors
|
||||
int32
|
||||
Gradient::CountColors() const
|
||||
{
|
||||
return fColors.CountItems();
|
||||
}
|
||||
|
||||
// ColorAt
|
||||
color_step*
|
||||
Gradient::ColorAt(int32 index) const
|
||||
{
|
||||
return (color_step*)fColors.ItemAt(index);
|
||||
}
|
||||
|
||||
// ColorAtFast
|
||||
color_step*
|
||||
Gradient::ColorAtFast(int32 index) const
|
||||
{
|
||||
return (color_step*)fColors.ItemAtFast(index);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// SetType
|
||||
void
|
||||
Gradient::SetType(gradient_type type)
|
||||
{
|
||||
if (fType != type) {
|
||||
fType = type;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
// SetInterpolation
|
||||
void
|
||||
Gradient::SetInterpolation(interpolation_type type)
|
||||
{
|
||||
if (fInterpolation != type) {
|
||||
fInterpolation = type;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
// SetInheritTransformation
|
||||
void
|
||||
Gradient::SetInheritTransformation(bool inherit)
|
||||
{
|
||||
if (fInheritTransformation != inherit) {
|
||||
fInheritTransformation = inherit;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// gauss
|
||||
inline double
|
||||
gauss(double f)
|
||||
{
|
||||
// this aint' a real gauss function
|
||||
if (f > 0.0) {
|
||||
if (f < 0.5)
|
||||
return (1.0 - 2.0 * f*f);
|
||||
|
||||
f = 1.0 - f;
|
||||
return (2.0 * f*f);
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
// MakeGradient
|
||||
void
|
||||
Gradient::MakeGradient(uint32* colors, int32 count) const
|
||||
{
|
||||
color_step* from = ColorAt(0);
|
||||
|
||||
if (!from)
|
||||
return;
|
||||
|
||||
// find the step with the lowest offset
|
||||
for (int32 i = 0; color_step* step = ColorAt(i); i++) {
|
||||
if (step->offset < from->offset)
|
||||
from = step;
|
||||
}
|
||||
|
||||
// current index into "colors" array
|
||||
int32 index = (int32)floorf(count * from->offset + 0.5);
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
if (index > count)
|
||||
index = count;
|
||||
// make sure we fill the entire array
|
||||
if (index > 0) {
|
||||
uint8* c = (uint8*)&colors[0];
|
||||
for (int32 i = 0; i < index; i++) {
|
||||
c[0] = from->color.red;
|
||||
c[1] = from->color.green;
|
||||
c[2] = from->color.blue;
|
||||
c[3] = from->color.alpha;
|
||||
c += 4;
|
||||
}
|
||||
}
|
||||
|
||||
// put all steps that we need to interpolate to into a list
|
||||
BList nextSteps(fColors.CountItems() - 1);
|
||||
for (int32 i = 0; color_step* step = ColorAt(i); i++) {
|
||||
if (step != from)
|
||||
nextSteps.AddItem((void*)step);
|
||||
}
|
||||
|
||||
// interpolate "from" to "to"
|
||||
while (!nextSteps.IsEmpty()) {
|
||||
|
||||
// find the step with the next offset
|
||||
color_step* to = NULL;
|
||||
float nextOffsetDist = 2.0;
|
||||
for (int32 i = 0; color_step* step = (color_step*)nextSteps.ItemAt(i); i++) {
|
||||
float d = step->offset - from->offset;
|
||||
if (d < nextOffsetDist && d >= 0) {
|
||||
to = step;
|
||||
nextOffsetDist = d;
|
||||
}
|
||||
}
|
||||
if (!to)
|
||||
break;
|
||||
|
||||
nextSteps.RemoveItem((void*)to);
|
||||
|
||||
// interpolate
|
||||
int32 offset = (int32)floorf((count - 1) * to->offset + 0.5);
|
||||
if (offset >= count)
|
||||
offset = count - 1;
|
||||
int32 dist = offset - index;
|
||||
if (dist >= 0) {
|
||||
uint8* c = (uint8*)&colors[index];
|
||||
#if GAMMA_BLEND
|
||||
uint16 fromRed = kGammaTable[from->color.red];
|
||||
uint16 fromGreen = kGammaTable[from->color.green];
|
||||
uint16 fromBlue = kGammaTable[from->color.blue];
|
||||
uint16 toRed = kGammaTable[to->color.red];
|
||||
uint16 toGreen = kGammaTable[to->color.green];
|
||||
uint16 toBlue = kGammaTable[to->color.blue];
|
||||
|
||||
for (int32 i = index; i <= offset; i++) {
|
||||
float f = (float)(offset - i) / (float)(dist + 1);
|
||||
if (fInterpolation == INTERPOLATION_SMOOTH)
|
||||
f = gauss(1.0 - f);
|
||||
float t = 1.0 - f;
|
||||
c[0] = kInverseGammaTable[(uint16)floor(fromBlue * f + toBlue * t + 0.5)];
|
||||
c[1] = kInverseGammaTable[(uint16)floor(fromGreen * f + toGreen * t + 0.5)];
|
||||
c[2] = kInverseGammaTable[(uint16)floor(fromRed * f + toRed * t + 0.5)];
|
||||
c[3] = (uint8)floor(from->color.alpha * f + to->color.alpha * t + 0.5);
|
||||
c += 4;
|
||||
}
|
||||
#else // GAMMA_BLEND
|
||||
for (int32 i = index; i <= offset; i++) {
|
||||
float f = (float)(offset - i) / (float)(dist + 1);
|
||||
if (fInterpolation == INTERPOLATION_SMOOTH)
|
||||
f = gauss(1.0 - f);
|
||||
float t = 1.0 - f;
|
||||
c[0] = (uint8)floor(from->color.red * f + to->color.red * t + 0.5);
|
||||
c[1] = (uint8)floor(from->color.green * f + to->color.green * t + 0.5);
|
||||
c[2] = (uint8)floor(from->color.blue * f + to->color.blue * t + 0.5);
|
||||
c[3] = (uint8)floor(from->color.alpha * f + to->color.alpha * t + 0.5);
|
||||
c += 4;
|
||||
}
|
||||
#endif // GAMMA_BLEND
|
||||
}
|
||||
index = offset + 1;
|
||||
// the current "to" will be the "from" in the next interpolation
|
||||
from = to;
|
||||
}
|
||||
// make sure we fill the entire array
|
||||
if (index < count) {
|
||||
uint8* c = (uint8*)&colors[index];
|
||||
for (int32 i = index; i < count; i++) {
|
||||
c[0] = from->color.red;
|
||||
c[1] = from->color.green;
|
||||
c[2] = from->color.blue;
|
||||
c[3] = from->color.alpha;
|
||||
c += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// string_for_type
|
||||
static const char*
|
||||
string_for_type(gradient_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case GRADIENT_LINEAR:
|
||||
return "GRADIENT_LINEAR";
|
||||
case GRADIENT_CIRCULAR:
|
||||
return "GRADIENT_CIRCULAR";
|
||||
case GRADIENT_DIAMONT:
|
||||
return "GRADIENT_DIAMONT";
|
||||
case GRADIENT_CONIC:
|
||||
return "GRADIENT_CONIC";
|
||||
case GRADIENT_XY:
|
||||
return "GRADIENT_XY";
|
||||
case GRADIENT_SQRT_XY:
|
||||
return "GRADIENT_SQRT_XY";
|
||||
}
|
||||
return "<unkown>";
|
||||
}
|
||||
|
||||
//string_for_interpolation
|
||||
static const char*
|
||||
string_for_interpolation(interpolation_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case INTERPOLATION_LINEAR:
|
||||
return "INTERPOLATION_LINEAR";
|
||||
case INTERPOLATION_SMOOTH:
|
||||
return "INTERPOLATION_SMOOTH";
|
||||
}
|
||||
return "<unkown>";
|
||||
}
|
||||
|
||||
// GradientArea
|
||||
BRect
|
||||
Gradient::GradientArea() const
|
||||
{
|
||||
BRect area(0, 0, 63, 63);
|
||||
switch (fType) {
|
||||
case GRADIENT_LINEAR:
|
||||
case GRADIENT_CIRCULAR:
|
||||
case GRADIENT_DIAMONT:
|
||||
case GRADIENT_CONIC:
|
||||
case GRADIENT_XY:
|
||||
case GRADIENT_SQRT_XY:
|
||||
break;
|
||||
}
|
||||
return area;
|
||||
}
|
||||
|
||||
// TransformationChanged()
|
||||
void
|
||||
Gradient::TransformationChanged()
|
||||
{
|
||||
Notify();
|
||||
}
|
||||
|
||||
// PrintToStream
|
||||
void
|
||||
Gradient::PrintToStream() const
|
||||
{
|
||||
printf("Gradient: type: %s, interpolation: %s, inherits transform: %d\n",
|
||||
string_for_type(fType),
|
||||
string_for_interpolation(fInterpolation),
|
||||
fInheritTransformation);
|
||||
for (int32 i = 0; color_step* step = ColorAt(i); i++) {
|
||||
printf(" %ld: offset: %.1f -> color(%d, %d, %d, %d)\n",
|
||||
i, step->offset,
|
||||
step->color.red,
|
||||
step->color.green,
|
||||
step->color.blue,
|
||||
step->color.alpha);
|
||||
}
|
||||
}
|
||||
|
||||
// _MakeEmpty
|
||||
void
|
||||
Gradient::_MakeEmpty()
|
||||
{
|
||||
int32 count = CountColors();
|
||||
for (int32 i = 0; i < count; i++)
|
||||
delete ColorAtFast(i);
|
||||
fColors.MakeEmpty();
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef GRADIENT_H
|
||||
#define GRADIENT_H
|
||||
|
||||
#include <GraphicsDefs.h>
|
||||
#include <List.h>
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
# include <Archivable.h>
|
||||
|
||||
# include "Observable.h"
|
||||
#endif ICON_O_MATIC
|
||||
|
||||
#include "Transformable.h"
|
||||
|
||||
class BMessage;
|
||||
|
||||
enum gradient_type {
|
||||
GRADIENT_LINEAR = 0,
|
||||
GRADIENT_CIRCULAR,
|
||||
GRADIENT_DIAMONT,
|
||||
GRADIENT_CONIC,
|
||||
GRADIENT_XY,
|
||||
GRADIENT_SQRT_XY,
|
||||
};
|
||||
|
||||
enum interpolation_type {
|
||||
INTERPOLATION_LINEAR = 0,
|
||||
INTERPOLATION_SMOOTH,
|
||||
};
|
||||
|
||||
struct color_step {
|
||||
color_step(const rgb_color c, float o);
|
||||
color_step(uint8 r, uint8 g, uint8 b, uint8 a, float o);
|
||||
color_step(const color_step& other);
|
||||
color_step();
|
||||
|
||||
bool operator!=(const color_step& other) const;
|
||||
|
||||
rgb_color color;
|
||||
float offset;
|
||||
};
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
class Gradient : public BArchivable,
|
||||
public Observable,
|
||||
public Transformable {
|
||||
#else
|
||||
class Gradient : public Transformable {
|
||||
#endif
|
||||
|
||||
public:
|
||||
Gradient(bool empty = false);
|
||||
#ifdef ICON_O_MATIC
|
||||
Gradient(BMessage* archive);
|
||||
#endif
|
||||
Gradient(const Gradient& other);
|
||||
virtual ~Gradient();
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
status_t Archive(BMessage* into, bool deep = true) const;
|
||||
#else
|
||||
inline void Notify() {}
|
||||
#endif
|
||||
|
||||
Gradient& operator=(const Gradient& other);
|
||||
|
||||
bool operator==(const Gradient& other) const;
|
||||
bool operator!=(const Gradient& other) const;
|
||||
|
||||
void SetColors(const Gradient& other);
|
||||
|
||||
|
||||
int32 AddColor(const rgb_color& color, float offset);
|
||||
bool AddColor(const color_step& color, int32 index);
|
||||
|
||||
bool RemoveColor(int32 index);
|
||||
|
||||
bool SetColor(int32 index, const color_step& step);
|
||||
bool SetColor(int32 index, const rgb_color& color);
|
||||
bool SetOffset(int32 index, float offset);
|
||||
|
||||
int32 CountColors() const;
|
||||
color_step* ColorAt(int32 index) const;
|
||||
color_step* ColorAtFast(int32 index) const;
|
||||
|
||||
void SetType(gradient_type type);
|
||||
gradient_type Type() const
|
||||
{ return fType; }
|
||||
|
||||
void SetInterpolation(interpolation_type type);
|
||||
interpolation_type Interpolation() const
|
||||
{ return fInterpolation; }
|
||||
|
||||
void SetInheritTransformation(bool inherit);
|
||||
bool InheritTransformation() const
|
||||
{ return fInheritTransformation; }
|
||||
|
||||
void MakeGradient(uint32* colors,
|
||||
int32 count) const;
|
||||
|
||||
BRect GradientArea() const;
|
||||
virtual void TransformationChanged();
|
||||
|
||||
void PrintToStream() const;
|
||||
|
||||
private:
|
||||
void _MakeEmpty();
|
||||
|
||||
BList fColors;
|
||||
gradient_type fType;
|
||||
interpolation_type fInterpolation;
|
||||
bool fInheritTransformation;
|
||||
};
|
||||
|
||||
|
||||
#endif // GRADIENT_H
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Style.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
# include <Message.h>
|
||||
|
||||
# include "ui_defines.h"
|
||||
#else
|
||||
# define kWhite (rgb_color){ 255, 255, 255, 255 }
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
#include "Gradient.h"
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// constructor
|
||||
Style::Style()
|
||||
#ifdef ICON_O_MATIC
|
||||
: IconObject("<style>"),
|
||||
Observer(),
|
||||
#else
|
||||
:
|
||||
#endif
|
||||
|
||||
fColor(kWhite),
|
||||
fGradient(NULL),
|
||||
fColors(NULL),
|
||||
|
||||
fGammaCorrectedColors(NULL),
|
||||
fGammaCorrectedColorsValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
// constructor
|
||||
Style::Style(const rgb_color& color)
|
||||
#ifdef ICON_O_MATIC
|
||||
: IconObject("<style>"),
|
||||
Observer(),
|
||||
#else
|
||||
:
|
||||
#endif
|
||||
|
||||
fColor(color),
|
||||
fGradient(NULL),
|
||||
fColors(NULL),
|
||||
|
||||
fGammaCorrectedColors(NULL),
|
||||
fGammaCorrectedColorsValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
// constructor
|
||||
Style::Style(const Style& other)
|
||||
#ifdef ICON_O_MATIC
|
||||
: IconObject(other),
|
||||
Observer(),
|
||||
#else
|
||||
:
|
||||
#endif
|
||||
|
||||
fColor(other.fColor),
|
||||
fGradient(NULL),
|
||||
fColors(NULL),
|
||||
|
||||
fGammaCorrectedColors(NULL),
|
||||
fGammaCorrectedColorsValid(false)
|
||||
{
|
||||
SetGradient(other.fGradient);
|
||||
}
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// constructor
|
||||
Style::Style(BMessage* archive)
|
||||
: IconObject(archive),
|
||||
Observer(),
|
||||
|
||||
fColor(kWhite),
|
||||
fGradient(NULL),
|
||||
fColors(NULL),
|
||||
|
||||
fGammaCorrectedColors(NULL),
|
||||
fGammaCorrectedColorsValid(false)
|
||||
{
|
||||
if (!archive)
|
||||
return;
|
||||
|
||||
if (archive->FindInt32("color", (int32*)&fColor) < B_OK)
|
||||
fColor = kWhite;
|
||||
|
||||
BMessage gradientArchive;
|
||||
if (archive->FindMessage("gradient", &gradientArchive) == B_OK) {
|
||||
::Gradient gradient(&gradientArchive);
|
||||
SetGradient(&gradient);
|
||||
}
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
// destructor
|
||||
Style::~Style()
|
||||
{
|
||||
SetGradient(NULL);
|
||||
}
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// ObjectChanged
|
||||
void
|
||||
Style::ObjectChanged(const Observable* object)
|
||||
{
|
||||
if (object == fGradient && fColors) {
|
||||
fGradient->MakeGradient((uint32*)fColors, 256);
|
||||
fGammaCorrectedColorsValid = false;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// Archive
|
||||
status_t
|
||||
Style::Archive(BMessage* into, bool deep) const
|
||||
{
|
||||
status_t ret = IconObject::Archive(into, deep);
|
||||
|
||||
if (ret == B_OK)
|
||||
ret = into->AddInt32("color", (uint32&)fColor);
|
||||
|
||||
if (ret == B_OK && fGradient) {
|
||||
BMessage gradientArchive;
|
||||
ret = fGradient->Archive(&gradientArchive, deep);
|
||||
if (ret == B_OK)
|
||||
ret = into->AddMessage("gradient", &gradientArchive);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
// SetColor
|
||||
void
|
||||
Style::SetColor(const rgb_color& color)
|
||||
{
|
||||
if ((uint32&)fColor == (uint32&)color)
|
||||
return;
|
||||
|
||||
fColor = color;
|
||||
Notify();
|
||||
}
|
||||
|
||||
// SetGradient
|
||||
void
|
||||
Style::SetGradient(const ::Gradient* gradient)
|
||||
{
|
||||
if (!fGradient && !gradient)
|
||||
return;
|
||||
|
||||
if (gradient) {
|
||||
if (!fGradient) {
|
||||
fGradient = new (nothrow) ::Gradient(*gradient);
|
||||
if (fGradient) {
|
||||
#ifdef ICON_O_MATIC
|
||||
fGradient->AddObserver(this);
|
||||
#endif
|
||||
// generate gradient
|
||||
fColors = new agg::rgba8[256];
|
||||
fGradient->MakeGradient((uint32*)fColors, 256);
|
||||
fGammaCorrectedColorsValid = false;
|
||||
|
||||
Notify();
|
||||
}
|
||||
} else {
|
||||
if (*fGradient != *gradient) {
|
||||
*fGradient = *gradient;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#ifdef ICON_O_MATIC
|
||||
fGradient->RemoveObserver(this);
|
||||
#endif
|
||||
delete[] fColors;
|
||||
delete[] fGammaCorrectedColors;
|
||||
fColors = NULL;
|
||||
fGammaCorrectedColors = NULL;
|
||||
fGradient = NULL;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
// GammaCorrectedColors
|
||||
const agg::rgba8*
|
||||
Style::GammaCorrectedColors(const GammaTable& table) const
|
||||
{
|
||||
if (!fColors)
|
||||
return NULL;
|
||||
|
||||
if (!fGammaCorrectedColors)
|
||||
fGammaCorrectedColors = new agg::rgba8[256];
|
||||
|
||||
if (!fGammaCorrectedColorsValid) {
|
||||
for (int32 i = 0; i < 256; i++) {
|
||||
fGammaCorrectedColors[i].r = table.dir(fColors[i].r);
|
||||
fGammaCorrectedColors[i].g = table.dir(fColors[i].g);
|
||||
fGammaCorrectedColors[i].b = table.dir(fColors[i].b);
|
||||
fGammaCorrectedColors[i].a = fColors[i].a;
|
||||
fGammaCorrectedColors[i].premultiply();
|
||||
}
|
||||
fGammaCorrectedColorsValid = true;
|
||||
}
|
||||
|
||||
return fGammaCorrectedColors;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef STYLE_H
|
||||
#define STYLE_H
|
||||
|
||||
#include <GraphicsDefs.h>
|
||||
|
||||
#include <agg_color_rgba.h>
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
# include "IconObject.h"
|
||||
# include "Observer.h"
|
||||
#endif
|
||||
|
||||
#include "IconRenderer.h"
|
||||
// TODO: put GammaTable into its own file
|
||||
|
||||
class Gradient;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
class Style : public IconObject,
|
||||
public Observer {
|
||||
#else
|
||||
class Style {
|
||||
#endif
|
||||
public:
|
||||
Style();
|
||||
Style(const Style& other);
|
||||
Style(const rgb_color& color);
|
||||
#ifdef ICON_O_MATIC
|
||||
Style(BMessage* archive);
|
||||
#endif
|
||||
virtual ~Style();
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// Observer interface
|
||||
virtual void ObjectChanged(const Observable* object);
|
||||
|
||||
// Style
|
||||
status_t Archive(BMessage* into,
|
||||
bool deep = true) const;
|
||||
#else
|
||||
inline void Notify() {}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
void SetColor(const rgb_color& color);
|
||||
inline rgb_color Color() const
|
||||
{ return fColor; }
|
||||
|
||||
void SetGradient(const ::Gradient* gradient);
|
||||
::Gradient* Gradient() const
|
||||
{ return fGradient; }
|
||||
|
||||
const agg::rgba8* Colors() const
|
||||
{ return fColors; }
|
||||
|
||||
const agg::rgba8* GammaCorrectedColors(
|
||||
const GammaTable& table) const;
|
||||
|
||||
private:
|
||||
rgb_color fColor;
|
||||
::Gradient* fGradient;
|
||||
|
||||
// hold gradient color array
|
||||
agg::rgba8* fColors;
|
||||
|
||||
// for caching gamma corrected gradient color array
|
||||
mutable agg::rgba8* fGammaCorrectedColors;
|
||||
mutable bool fGammaCorrectedColorsValid;
|
||||
};
|
||||
|
||||
#endif // STYLE_H
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "StyleContainer.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include "Style.h"
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
StyleContainerListener::StyleContainerListener() {}
|
||||
StyleContainerListener::~StyleContainerListener() {}
|
||||
#endif
|
||||
|
||||
// constructor
|
||||
StyleContainer::StyleContainer()
|
||||
#ifdef ICON_O_MATIC
|
||||
: fStyles(32),
|
||||
fListeners(2)
|
||||
#else
|
||||
: fStyles(32)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
StyleContainer::~StyleContainer()
|
||||
{
|
||||
#ifdef ICON_O_MATIC
|
||||
int32 count = fListeners.CountItems();
|
||||
if (count > 0) {
|
||||
debugger("~StyleContainer() - there are still"
|
||||
"listeners attached\n");
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
_MakeEmpty();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// AddStyle
|
||||
bool
|
||||
StyleContainer::AddStyle(Style* style)
|
||||
{
|
||||
if (!style)
|
||||
return false;
|
||||
|
||||
// prevent adding the same style twice
|
||||
if (HasStyle(style))
|
||||
return false;
|
||||
|
||||
if (fStyles.AddItem((void*)style)) {
|
||||
#ifdef ICON_O_MATIC
|
||||
_NotifyStyleAdded(style);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
fprintf(stderr, "StyleContainer::AddStyle() - out of memory!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemoveStyle
|
||||
bool
|
||||
StyleContainer::RemoveStyle(Style* style)
|
||||
{
|
||||
if (fStyles.RemoveItem((void*)style)) {
|
||||
#ifdef ICON_O_MATIC
|
||||
_NotifyStyleRemoved(style);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemoveStyle
|
||||
Style*
|
||||
StyleContainer::RemoveStyle(int32 index)
|
||||
{
|
||||
Style* style = (Style*)fStyles.RemoveItem(index);
|
||||
if (style) {
|
||||
#ifdef ICON_O_MATIC
|
||||
_NotifyStyleRemoved(style);
|
||||
#endif
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
// MakeEmpty
|
||||
void
|
||||
StyleContainer::MakeEmpty()
|
||||
{
|
||||
_MakeEmpty();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// CountStyles
|
||||
int32
|
||||
StyleContainer::CountStyles() const
|
||||
{
|
||||
return fStyles.CountItems();
|
||||
}
|
||||
|
||||
// HasStyle
|
||||
bool
|
||||
StyleContainer::HasStyle(Style* style) const
|
||||
{
|
||||
return fStyles.HasItem((void*)style);
|
||||
}
|
||||
|
||||
// IndexOf
|
||||
int32
|
||||
StyleContainer::IndexOf(Style* style) const
|
||||
{
|
||||
return fStyles.IndexOf((void*)style);
|
||||
}
|
||||
|
||||
// StyleAt
|
||||
Style*
|
||||
StyleContainer::StyleAt(int32 index) const
|
||||
{
|
||||
return (Style*)fStyles.ItemAt(index);
|
||||
}
|
||||
|
||||
// StyleAtFast
|
||||
Style*
|
||||
StyleContainer::StyleAtFast(int32 index) const
|
||||
{
|
||||
return (Style*)fStyles.ItemAtFast(index);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
|
||||
// AddListener
|
||||
bool
|
||||
StyleContainer::AddListener(StyleContainerListener* listener)
|
||||
{
|
||||
if (listener && !fListeners.HasItem((void*)listener))
|
||||
return fListeners.AddItem(listener);
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemoveListener
|
||||
bool
|
||||
StyleContainer::RemoveListener(StyleContainerListener* listener)
|
||||
{
|
||||
return fListeners.RemoveItem(listener);
|
||||
}
|
||||
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _MakeEmpty
|
||||
void
|
||||
StyleContainer::_MakeEmpty()
|
||||
{
|
||||
int32 count = CountStyles();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Style* style = StyleAtFast(i);
|
||||
#ifdef ICON_O_MATIC
|
||||
_NotifyStyleRemoved(style);
|
||||
style->Release();
|
||||
#else
|
||||
delete style;
|
||||
#endif
|
||||
}
|
||||
fStyles.MakeEmpty();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
|
||||
// _NotifyStyleAdded
|
||||
void
|
||||
StyleContainer::_NotifyStyleAdded(Style* style) const
|
||||
{
|
||||
BList listeners(fListeners);
|
||||
int32 count = listeners.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
StyleContainerListener* listener
|
||||
= (StyleContainerListener*)listeners.ItemAtFast(i);
|
||||
listener->StyleAdded(style);
|
||||
}
|
||||
}
|
||||
|
||||
// _NotifyStyleRemoved
|
||||
void
|
||||
StyleContainer::_NotifyStyleRemoved(Style* style) const
|
||||
{
|
||||
BList listeners(fListeners);
|
||||
int32 count = listeners.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
StyleContainerListener* listener
|
||||
= (StyleContainerListener*)listeners.ItemAtFast(i);
|
||||
listener->StyleRemoved(style);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef STYLE_MANAGER_H
|
||||
#define STYLE_MANAGER_H
|
||||
|
||||
#include <List.h>
|
||||
|
||||
class Style;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
class StyleContainerListener {
|
||||
public:
|
||||
StyleContainerListener();
|
||||
virtual ~StyleContainerListener();
|
||||
|
||||
virtual void StyleAdded(Style* style) = 0;
|
||||
virtual void StyleRemoved(Style* style) = 0;
|
||||
};
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
class StyleContainer {
|
||||
public:
|
||||
StyleContainer();
|
||||
virtual ~StyleContainer();
|
||||
|
||||
bool AddStyle(Style* style);
|
||||
bool RemoveStyle(Style* style);
|
||||
Style* RemoveStyle(int32 index);
|
||||
|
||||
void MakeEmpty();
|
||||
|
||||
int32 CountStyles() const;
|
||||
bool HasStyle(Style* style) const;
|
||||
int32 IndexOf(Style* style) const;
|
||||
|
||||
Style* StyleAt(int32 index) const;
|
||||
Style* StyleAtFast(int32 index) const;
|
||||
|
||||
private:
|
||||
BList fStyles;
|
||||
|
||||
void _MakeEmpty();
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
public:
|
||||
bool AddListener(StyleContainerListener* listener);
|
||||
bool RemoveListener(StyleContainerListener* listener);
|
||||
|
||||
private:
|
||||
void _NotifyStyleAdded(Style* style) const;
|
||||
void _NotifyStyleRemoved(Style* style) const;
|
||||
|
||||
BList fListeners;
|
||||
#endif // ICON_O_MATIC
|
||||
};
|
||||
|
||||
#endif // STYLE_MANAGER_H
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Transformable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// constructor
|
||||
Transformable::Transformable()
|
||||
: agg::trans_affine()
|
||||
{
|
||||
}
|
||||
|
||||
// copy constructor
|
||||
Transformable::Transformable(const Transformable& other)
|
||||
: agg::trans_affine(other)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
Transformable::~Transformable()
|
||||
{
|
||||
}
|
||||
|
||||
// StoreTo
|
||||
void
|
||||
Transformable::StoreTo(double matrix[matrix_size]) const
|
||||
{
|
||||
store_to(matrix);
|
||||
}
|
||||
|
||||
// LoadFrom
|
||||
void
|
||||
Transformable::LoadFrom(const double matrix[matrix_size])
|
||||
{
|
||||
// before calling the potentially heavy TransformationChanged()
|
||||
// hook function, make sure that the transformation
|
||||
// really changed
|
||||
Transformable t;
|
||||
t.load_from(matrix);
|
||||
if (*this != t) {
|
||||
load_from(matrix);
|
||||
TransformationChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// SetTransform
|
||||
void
|
||||
Transformable::SetTransform(const Transformable& other)
|
||||
{
|
||||
if (*this != other) {
|
||||
*this = other;
|
||||
TransformationChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// operator=
|
||||
Transformable&
|
||||
Transformable::operator=(const Transformable& other)
|
||||
{
|
||||
if (other != *this) {
|
||||
reset();
|
||||
multiply(other);
|
||||
TransformationChanged();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Multiply
|
||||
Transformable&
|
||||
Transformable::Multiply(const Transformable& other)
|
||||
{
|
||||
if (!other.IsIdentity()) {
|
||||
multiply(other);
|
||||
TransformationChanged();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Reset
|
||||
void
|
||||
Transformable::Reset()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
// Invert
|
||||
void
|
||||
Transformable::Invert()
|
||||
{
|
||||
invert();
|
||||
}
|
||||
|
||||
// IsIdentity
|
||||
bool
|
||||
Transformable::IsIdentity() const
|
||||
{
|
||||
double m[matrix_size];
|
||||
store_to(m);
|
||||
if (m[0] == 1.0 &&
|
||||
m[1] == 0.0 &&
|
||||
m[2] == 0.0 &&
|
||||
m[3] == 1.0 &&
|
||||
m[4] == 0.0 &&
|
||||
m[5] == 0.0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// IsTranslationOnly
|
||||
bool
|
||||
Transformable::IsTranslationOnly() const
|
||||
{
|
||||
double m[matrix_size];
|
||||
store_to(m);
|
||||
if (m[0] == 1.0 &&
|
||||
m[1] == 0.0 &&
|
||||
m[2] == 0.0 &&
|
||||
m[3] == 1.0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// IsNotDistorted
|
||||
bool
|
||||
Transformable::IsNotDistorted() const
|
||||
{
|
||||
double m[matrix_size];
|
||||
store_to(m);
|
||||
return (m[0] == m[3]);
|
||||
}
|
||||
|
||||
// IsValid
|
||||
bool
|
||||
Transformable::IsValid() const
|
||||
{
|
||||
double m[matrix_size];
|
||||
store_to(m);
|
||||
return ((m[0] * m[3] - m[1] * m[2]) != 0.0);
|
||||
}
|
||||
|
||||
// operator==
|
||||
bool
|
||||
Transformable::operator==(const Transformable& other) const
|
||||
{
|
||||
double m1[matrix_size];
|
||||
other.store_to(m1);
|
||||
double m2[matrix_size];
|
||||
store_to(m2);
|
||||
return memcmp(m1, m2, sizeof(m1)) == 0;
|
||||
}
|
||||
|
||||
// operator!=
|
||||
bool
|
||||
Transformable::operator!=(const Transformable& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
// Transform
|
||||
void
|
||||
Transformable::Transform(double* x, double* y) const
|
||||
{
|
||||
transform(x, y);
|
||||
}
|
||||
|
||||
// Transform
|
||||
void
|
||||
Transformable::Transform(BPoint* point) const
|
||||
{
|
||||
if (point) {
|
||||
double x = point->x;
|
||||
double y = point->y;
|
||||
|
||||
transform(&x, &y);
|
||||
|
||||
point->x = x;
|
||||
point->y = y;
|
||||
}
|
||||
}
|
||||
|
||||
// Transform
|
||||
BPoint
|
||||
Transformable::Transform(const BPoint& point) const
|
||||
{
|
||||
BPoint p(point);
|
||||
Transform(&p);
|
||||
return p;
|
||||
}
|
||||
|
||||
// InverseTransform
|
||||
void
|
||||
Transformable::InverseTransform(double* x, double* y) const
|
||||
{
|
||||
inverse_transform(x, y);
|
||||
}
|
||||
|
||||
// InverseTransform
|
||||
void
|
||||
Transformable::InverseTransform(BPoint* point) const
|
||||
{
|
||||
if (point) {
|
||||
double x = point->x;
|
||||
double y = point->y;
|
||||
|
||||
inverse_transform(&x, &y);
|
||||
|
||||
point->x = x;
|
||||
point->y = y;
|
||||
}
|
||||
}
|
||||
|
||||
// InverseTransform
|
||||
BPoint
|
||||
Transformable::InverseTransform(const BPoint& point) const
|
||||
{
|
||||
BPoint p(point);
|
||||
InverseTransform(&p);
|
||||
return p;
|
||||
}
|
||||
|
||||
inline float
|
||||
min4(float a, float b, float c, float d)
|
||||
{
|
||||
return min_c(a, min_c(b, min_c(c, d)));
|
||||
}
|
||||
|
||||
inline float
|
||||
max4(float a, float b, float c, float d)
|
||||
{
|
||||
return max_c(a, max_c(b, max_c(c, d)));
|
||||
}
|
||||
|
||||
// TransformBounds
|
||||
BRect
|
||||
Transformable::TransformBounds(BRect bounds) const
|
||||
{
|
||||
if (bounds.IsValid()) {
|
||||
BPoint lt(bounds.left, bounds.top);
|
||||
BPoint rt(bounds.right, bounds.top);
|
||||
BPoint lb(bounds.left, bounds.bottom);
|
||||
BPoint rb(bounds.right, bounds.bottom);
|
||||
|
||||
Transform(<);
|
||||
Transform(&rt);
|
||||
Transform(&lb);
|
||||
Transform(&rb);
|
||||
|
||||
return BRect(floorf(min4(lt.x, rt.x, lb.x, rb.x)),
|
||||
floorf(min4(lt.y, rt.y, lb.y, rb.y)),
|
||||
ceilf(max4(lt.x, rt.x, lb.x, rb.x)),
|
||||
ceilf(max4(lt.y, rt.y, lb.y, rb.y)));
|
||||
}
|
||||
return bounds;
|
||||
}
|
||||
|
||||
// TranslateBy
|
||||
void
|
||||
Transformable::TranslateBy(BPoint offset)
|
||||
{
|
||||
if (offset.x != 0.0 || offset.y != 0.0) {
|
||||
multiply(agg::trans_affine_translation(offset.x, offset.y));
|
||||
TransformationChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// RotateBy
|
||||
void
|
||||
Transformable::RotateBy(BPoint origin, double degrees)
|
||||
{
|
||||
if (degrees != 0.0) {
|
||||
multiply(agg::trans_affine_translation(-origin.x, -origin.y));
|
||||
multiply(agg::trans_affine_rotation(degrees * (PI / 180.0)));
|
||||
multiply(agg::trans_affine_translation(origin.x, origin.y));
|
||||
TransformationChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// ScaleBy
|
||||
void
|
||||
Transformable::ScaleBy(BPoint origin, double xScale, double yScale)
|
||||
{
|
||||
if (xScale != 1.0 || yScale != 1.0) {
|
||||
multiply(agg::trans_affine_translation(-origin.x, -origin.y));
|
||||
multiply(agg::trans_affine_scaling(xScale, yScale));
|
||||
multiply(agg::trans_affine_translation(origin.x, origin.y));
|
||||
TransformationChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// ShearBy
|
||||
void
|
||||
Transformable::ShearBy(BPoint origin, double xShear, double yShear)
|
||||
{
|
||||
if (xShear != 0.0 || yShear != 0.0) {
|
||||
multiply(agg::trans_affine_translation(-origin.x, -origin.y));
|
||||
multiply(agg::trans_affine_skewing(xShear, yShear));
|
||||
multiply(agg::trans_affine_translation(origin.x, origin.y));
|
||||
TransformationChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// TransformationChanged
|
||||
void
|
||||
Transformable::TransformationChanged()
|
||||
{
|
||||
// default implementation doesn't care
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef TRANSFORMABLE_H
|
||||
#define TRANSFORMABLE_H
|
||||
|
||||
#include <Rect.h>
|
||||
|
||||
#include <agg_trans_affine.h>
|
||||
|
||||
class Transformable : public agg::trans_affine {
|
||||
public:
|
||||
enum {
|
||||
matrix_size = 6,
|
||||
};
|
||||
|
||||
Transformable();
|
||||
Transformable(const Transformable& other);
|
||||
virtual ~Transformable();
|
||||
|
||||
void StoreTo(double matrix[matrix_size]) const;
|
||||
void LoadFrom(const double matrix[matrix_size]);
|
||||
|
||||
// set to or combine with other matrix
|
||||
void SetTransform(const Transformable& other);
|
||||
Transformable& operator=(const Transformable& other);
|
||||
Transformable& Multiply(const Transformable& other);
|
||||
virtual void Reset();
|
||||
|
||||
void Invert();
|
||||
|
||||
bool IsIdentity() const;
|
||||
bool IsTranslationOnly() const;
|
||||
bool IsNotDistorted() const;
|
||||
bool IsValid() const;
|
||||
|
||||
bool operator==(const Transformable& other) const;
|
||||
bool operator!=(const Transformable& other) const;
|
||||
|
||||
// transforms coordiantes
|
||||
void Transform(double* x, double* y) const;
|
||||
void Transform(BPoint* point) const;
|
||||
BPoint Transform(const BPoint& point) const;
|
||||
|
||||
void InverseTransform(double* x, double* y) const;
|
||||
void InverseTransform(BPoint* point) const;
|
||||
BPoint InverseTransform(const BPoint& point) const;
|
||||
|
||||
// transforms the rectangle "bounds" and
|
||||
// returns the *bounding box* of that
|
||||
BRect TransformBounds(BRect bounds) const;
|
||||
|
||||
// some convenience functions
|
||||
virtual void TranslateBy(BPoint offset);
|
||||
virtual void RotateBy(BPoint origin, double degrees);
|
||||
virtual void ScaleBy(BPoint origin, double xScale, double yScale);
|
||||
virtual void ShearBy(BPoint origin, double xShear, double yShear);
|
||||
|
||||
virtual void TransformationChanged();
|
||||
// hook function that is called when the transformation
|
||||
// is changed for some reason
|
||||
};
|
||||
|
||||
#endif // TRANSFORMABLE_H
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "AffineTransformer.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
# include <Message.h>
|
||||
|
||||
# include "CommonPropertyIDs.h"
|
||||
# include "Property.h"
|
||||
# include "PropertyObject.h"
|
||||
#endif
|
||||
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// constructor
|
||||
AffineTransformer::AffineTransformer(VertexSource& source)
|
||||
: Transformer(source, "Transformation"),
|
||||
Affine(source, *this)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// constructor
|
||||
AffineTransformer::AffineTransformer(VertexSource& source,
|
||||
BMessage* archive)
|
||||
: Transformer(source, archive),
|
||||
Affine(source, *this)
|
||||
{
|
||||
if (!archive)
|
||||
return;
|
||||
|
||||
int32 size = 6;
|
||||
const void* matrix;
|
||||
ssize_t dataSize = size * sizeof(double);
|
||||
if (archive->FindData("matrix", B_DOUBLE_TYPE,
|
||||
&matrix, &dataSize) == B_OK) {
|
||||
if (dataSize == (ssize_t)(size * sizeof(double)))
|
||||
load_from((const double*)matrix);
|
||||
}
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
// destructor
|
||||
AffineTransformer::~AffineTransformer()
|
||||
{
|
||||
}
|
||||
|
||||
// Clone
|
||||
Transformer*
|
||||
AffineTransformer::Clone(VertexSource& source) const
|
||||
{
|
||||
AffineTransformer* clone = new (nothrow) AffineTransformer(source);
|
||||
if (clone)
|
||||
clone->multiply(*this);
|
||||
return clone;
|
||||
}
|
||||
|
||||
// rewind
|
||||
void
|
||||
AffineTransformer::rewind(unsigned path_id)
|
||||
{
|
||||
Affine::rewind(path_id);
|
||||
}
|
||||
|
||||
// vertex
|
||||
unsigned
|
||||
AffineTransformer::vertex(double* x, double* y)
|
||||
{
|
||||
return Affine::vertex(x, y);
|
||||
}
|
||||
|
||||
// SetSource
|
||||
void
|
||||
AffineTransformer::SetSource(VertexSource& source)
|
||||
{
|
||||
Transformer::SetSource(source);
|
||||
Affine::attach(source);
|
||||
}
|
||||
|
||||
// ApproximationScale
|
||||
double
|
||||
AffineTransformer::ApproximationScale() const
|
||||
{
|
||||
return fSource.ApproximationScale() * scale();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
|
||||
// Archive
|
||||
status_t
|
||||
AffineTransformer::Archive(BMessage* into, bool deep) const
|
||||
{
|
||||
status_t ret = Transformer::Archive(into, deep);
|
||||
|
||||
if (ret == B_OK)
|
||||
into->what = archive_code;
|
||||
|
||||
if (ret == B_OK) {
|
||||
double matrix[6];
|
||||
store_to(matrix);
|
||||
ret = into->AddData("matrix", B_DOUBLE_TYPE,
|
||||
matrix, 6 * sizeof(double));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// MakePropertyObject
|
||||
PropertyObject*
|
||||
AffineTransformer::MakePropertyObject() const
|
||||
{
|
||||
PropertyObject* object = Transformer::MakePropertyObject();
|
||||
if (!object)
|
||||
return NULL;
|
||||
|
||||
// translation
|
||||
double tx;
|
||||
double ty;
|
||||
translation(&tx, &ty);
|
||||
object->AddProperty(new FloatProperty(PROPERTY_TRANSLATION_X, tx));
|
||||
object->AddProperty(new FloatProperty(PROPERTY_TRANSLATION_Y, ty));
|
||||
|
||||
// rotation
|
||||
object->AddProperty(new FloatProperty(PROPERTY_ROTATION,
|
||||
agg::rad2deg(rotation())));
|
||||
|
||||
// scale
|
||||
double scaleX;
|
||||
double scaleY;
|
||||
scaling(&scaleX, &scaleY);
|
||||
object->AddProperty(new FloatProperty(PROPERTY_SCALE_X, scaleX));
|
||||
object->AddProperty(new FloatProperty(PROPERTY_SCALE_Y, scaleY));
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
// SetToPropertyObject
|
||||
bool
|
||||
AffineTransformer::SetToPropertyObject(const PropertyObject* object)
|
||||
{
|
||||
AutoNotificationSuspender _(this);
|
||||
Transformer::SetToPropertyObject(object);
|
||||
|
||||
// current affine parameters
|
||||
double tx;
|
||||
double ty;
|
||||
translation(&tx, &ty);
|
||||
double r = rotation();
|
||||
double scaleX;
|
||||
double scaleY;
|
||||
scaling(&scaleX, &scaleY);
|
||||
|
||||
// properties
|
||||
double newTX = object->Value(PROPERTY_TRANSLATION_X, (float)tx);
|
||||
double newTY = object->Value(PROPERTY_TRANSLATION_Y, (float)ty);
|
||||
|
||||
double newR = object->Value(PROPERTY_ROTATION,
|
||||
(float)agg::rad2deg(r));
|
||||
newR = agg::deg2rad(newR);
|
||||
|
||||
double newScaleX = object->Value(PROPERTY_SCALE_X, (float)scaleX);
|
||||
double newScaleY = object->Value(PROPERTY_SCALE_Y, (float)scaleY);
|
||||
|
||||
if (newTX != tx || newTY != ty
|
||||
|| newR != r
|
||||
|| newScaleX != scaleX
|
||||
|| newScaleY != scaleY) {
|
||||
|
||||
reset();
|
||||
|
||||
multiply(agg::trans_affine_scaling(newScaleX, newScaleY));
|
||||
multiply(agg::trans_affine_rotation(newR));
|
||||
multiply(agg::trans_affine_translation(newTX, newTY));
|
||||
|
||||
Notify();
|
||||
}
|
||||
|
||||
return HasPendingNotifications();
|
||||
}
|
||||
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef AFFINE_TRANSFORMER_H
|
||||
#define AFFINE_TRANSFORMER_H
|
||||
|
||||
#include <agg_conv_transform.h>
|
||||
#include <agg_trans_affine.h>
|
||||
|
||||
#include "Transformer.h"
|
||||
|
||||
typedef agg::conv_transform<VertexSource,
|
||||
agg::trans_affine> Affine;
|
||||
|
||||
class AffineTransformer : public Transformer,
|
||||
public Affine,
|
||||
public agg::trans_affine {
|
||||
public:
|
||||
enum {
|
||||
archive_code = 'affn',
|
||||
};
|
||||
|
||||
AffineTransformer(
|
||||
VertexSource& source);
|
||||
#ifdef ICON_O_MATIC
|
||||
AffineTransformer(
|
||||
VertexSource& source,
|
||||
BMessage* archive);
|
||||
#endif
|
||||
virtual ~AffineTransformer();
|
||||
|
||||
virtual Transformer* Clone(VertexSource& source) const;
|
||||
|
||||
virtual void rewind(unsigned path_id);
|
||||
virtual unsigned vertex(double* x, double* y);
|
||||
|
||||
virtual void SetSource(VertexSource& source);
|
||||
|
||||
virtual double ApproximationScale() const;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// IconObject interface
|
||||
virtual status_t Archive(BMessage* into,
|
||||
bool deep = true) const;
|
||||
|
||||
virtual PropertyObject* MakePropertyObject() const;
|
||||
virtual bool SetToPropertyObject(
|
||||
const PropertyObject* object);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // AFFINE_TRANSFORMER_H
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "ContourTransformer.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
# include <Message.h>
|
||||
|
||||
# include "CommonPropertyIDs.h"
|
||||
# include "OptionProperty.h"
|
||||
# include "Property.h"
|
||||
# include "PropertyObject.h"
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// constructor
|
||||
ContourTransformer::ContourTransformer(VertexSource& source)
|
||||
: Transformer(source, "Contour"),
|
||||
Contour(source)
|
||||
{
|
||||
auto_detect_orientation(true);
|
||||
}
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// constructor
|
||||
ContourTransformer::ContourTransformer(VertexSource& source,
|
||||
BMessage* archive)
|
||||
: Transformer(source, archive),
|
||||
Contour(source)
|
||||
{
|
||||
auto_detect_orientation(true);
|
||||
|
||||
if (!archive)
|
||||
return;
|
||||
|
||||
int32 mode;
|
||||
if (archive->FindInt32("line join", &mode) == B_OK)
|
||||
line_join((agg::line_join_e)mode);
|
||||
|
||||
if (archive->FindInt32("inner join", &mode) == B_OK)
|
||||
inner_join((agg::inner_join_e)mode);
|
||||
|
||||
double value;
|
||||
if (archive->FindDouble("width", &value) == B_OK)
|
||||
width(value);
|
||||
|
||||
if (archive->FindDouble("miter limit", &value) == B_OK)
|
||||
miter_limit(value);
|
||||
|
||||
if (archive->FindDouble("inner miter limit", &value) == B_OK)
|
||||
inner_miter_limit(value);
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
// destructor
|
||||
ContourTransformer::~ContourTransformer()
|
||||
{
|
||||
}
|
||||
|
||||
// Clone
|
||||
Transformer*
|
||||
ContourTransformer::Clone(VertexSource& source) const
|
||||
{
|
||||
ContourTransformer* clone = new (nothrow) ContourTransformer(source);
|
||||
if (clone) {
|
||||
clone->line_join(line_join());
|
||||
clone->inner_join(inner_join());
|
||||
clone->width(width());
|
||||
clone->miter_limit(miter_limit());
|
||||
clone->inner_miter_limit(inner_miter_limit());
|
||||
clone->auto_detect_orientation(auto_detect_orientation());
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
// rewind
|
||||
void
|
||||
ContourTransformer::rewind(unsigned path_id)
|
||||
{
|
||||
Contour::rewind(path_id);
|
||||
}
|
||||
|
||||
// vertex
|
||||
unsigned
|
||||
ContourTransformer::vertex(double* x, double* y)
|
||||
{
|
||||
return Contour::vertex(x, y);
|
||||
}
|
||||
|
||||
// SetSource
|
||||
void
|
||||
ContourTransformer::SetSource(VertexSource& source)
|
||||
{
|
||||
Transformer::SetSource(source);
|
||||
Contour::attach(source);
|
||||
}
|
||||
|
||||
// ApproximationScale
|
||||
double
|
||||
ContourTransformer::ApproximationScale() const
|
||||
{
|
||||
return fSource.ApproximationScale() * width();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
|
||||
// Archive
|
||||
status_t
|
||||
ContourTransformer::Archive(BMessage* into, bool deep) const
|
||||
{
|
||||
status_t ret = Transformer::Archive(into, deep);
|
||||
|
||||
if (ret == B_OK)
|
||||
into->what = archive_code;
|
||||
|
||||
if (ret == B_OK)
|
||||
ret = into->AddInt32("line join", line_join());
|
||||
|
||||
if (ret == B_OK)
|
||||
ret = into->AddInt32("inner join", inner_join());
|
||||
|
||||
if (ret == B_OK)
|
||||
ret = into->AddDouble("width", width());
|
||||
|
||||
if (ret == B_OK)
|
||||
ret = into->AddDouble("miter limit", miter_limit());
|
||||
|
||||
if (ret == B_OK)
|
||||
ret = into->AddDouble("inner miter limit", inner_miter_limit());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// MakePropertyObject
|
||||
PropertyObject*
|
||||
ContourTransformer::MakePropertyObject() const
|
||||
{
|
||||
PropertyObject* object = Transformer::MakePropertyObject();
|
||||
if (!object)
|
||||
return NULL;
|
||||
|
||||
// width
|
||||
object->AddProperty(new FloatProperty(PROPERTY_WIDTH, width()));
|
||||
|
||||
// auto detect orientation
|
||||
object->AddProperty(new BoolProperty(PROPERTY_DETECT_ORIENTATION,
|
||||
auto_detect_orientation()));
|
||||
|
||||
// join mode
|
||||
OptionProperty* property = new OptionProperty(PROPERTY_JOIN_MODE);
|
||||
property->AddOption(agg::miter_join, "Miter");
|
||||
property->AddOption(agg::round_join, "Round");
|
||||
property->AddOption(agg::bevel_join, "Bevel");
|
||||
property->SetCurrentOptionID(line_join());
|
||||
|
||||
object->AddProperty(property);
|
||||
|
||||
// miter limit
|
||||
object->AddProperty(new FloatProperty(PROPERTY_MITER_LIMIT,
|
||||
miter_limit()));
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
// SetToPropertyObject
|
||||
bool
|
||||
ContourTransformer::SetToPropertyObject(const PropertyObject* object)
|
||||
{
|
||||
AutoNotificationSuspender _(this);
|
||||
Transformer::SetToPropertyObject(object);
|
||||
|
||||
// width
|
||||
float w = object->Value(PROPERTY_WIDTH, (float)width());
|
||||
if (w != width()) {
|
||||
width(w);
|
||||
Notify();
|
||||
}
|
||||
|
||||
// auto detect orientation
|
||||
bool ado = object->Value(PROPERTY_DETECT_ORIENTATION,
|
||||
auto_detect_orientation());
|
||||
if (ado != auto_detect_orientation()) {
|
||||
auto_detect_orientation(ado);
|
||||
Notify();
|
||||
}
|
||||
|
||||
// join mode
|
||||
OptionProperty* property = dynamic_cast<OptionProperty*>(
|
||||
object->FindProperty(PROPERTY_JOIN_MODE));
|
||||
if (property && line_join() != property->CurrentOptionID()) {
|
||||
line_join((agg::line_join_e)property->CurrentOptionID());
|
||||
Notify();
|
||||
}
|
||||
|
||||
// miter limit
|
||||
float l = object->Value(PROPERTY_MITER_LIMIT, (float)miter_limit());
|
||||
if (l != miter_limit()) {
|
||||
miter_limit(l);
|
||||
Notify();
|
||||
}
|
||||
|
||||
return HasPendingNotifications();
|
||||
}
|
||||
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef CONTOUR_TRANSFORMER_H
|
||||
#define CONTOUR_TRANSFORMER_H
|
||||
|
||||
#include <agg_conv_contour.h>
|
||||
|
||||
#include "Transformer.h"
|
||||
|
||||
typedef agg::conv_contour<VertexSource> Contour;
|
||||
|
||||
class ContourTransformer : public Transformer,
|
||||
public Contour {
|
||||
public:
|
||||
enum {
|
||||
archive_code = 'cntr',
|
||||
};
|
||||
|
||||
ContourTransformer(
|
||||
VertexSource& source);
|
||||
#ifdef ICON_O_MATIC
|
||||
ContourTransformer(
|
||||
VertexSource& source,
|
||||
BMessage* archive);
|
||||
#endif
|
||||
virtual ~ContourTransformer();
|
||||
|
||||
virtual Transformer* Clone(VertexSource& source) const;
|
||||
|
||||
virtual void rewind(unsigned path_id);
|
||||
virtual unsigned vertex(double* x, double* y);
|
||||
|
||||
virtual void SetSource(VertexSource& source);
|
||||
|
||||
virtual double ApproximationScale() const;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// IconObject interface
|
||||
virtual status_t Archive(BMessage* into,
|
||||
bool deep = true) const;
|
||||
|
||||
virtual PropertyObject* MakePropertyObject() const;
|
||||
virtual bool SetToPropertyObject(
|
||||
const PropertyObject* object);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // CONTOUR_TRANSFORMER_H
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "PathSource.h"
|
||||
|
||||
#include "PathContainer.h"
|
||||
#include "VectorPath.h"
|
||||
|
||||
// constructor
|
||||
PathSource::PathSource(PathContainer* paths)
|
||||
: VertexSource(),
|
||||
fPaths(paths),
|
||||
fAGGPath(),
|
||||
fAGGCurvedPath(fAGGPath)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
PathSource::~PathSource()
|
||||
{
|
||||
}
|
||||
|
||||
// rewind
|
||||
void
|
||||
PathSource::rewind(unsigned path_id)
|
||||
{
|
||||
fAGGCurvedPath.rewind(path_id);
|
||||
}
|
||||
|
||||
// vertex
|
||||
unsigned
|
||||
PathSource::vertex(double* x, double* y)
|
||||
{
|
||||
return fAGGCurvedPath.vertex(x, y);
|
||||
}
|
||||
|
||||
// WantsOpenPaths
|
||||
bool
|
||||
PathSource::WantsOpenPaths() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// ApproximationScale
|
||||
double
|
||||
PathSource::ApproximationScale() const
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// Update
|
||||
void
|
||||
PathSource::Update(bool leavePathsOpen, double approximationScale)
|
||||
{
|
||||
fAGGPath.remove_all();
|
||||
|
||||
int32 count = fPaths->CountPaths();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
fPaths->PathAtFast(i)->GetAGGPathStorage(fAGGPath);
|
||||
if (!leavePathsOpen)
|
||||
fAGGPath.close_polygon();
|
||||
}
|
||||
|
||||
fAGGCurvedPath.approximation_scale(approximationScale);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef PATH_SOURCE_H
|
||||
#define PATH_SOURCE_H
|
||||
|
||||
#include "Transformer.h"
|
||||
|
||||
#include "agg_path_storage.h"
|
||||
#include "agg_conv_curve.h"
|
||||
|
||||
class PathContainer;
|
||||
class VectorPath;
|
||||
|
||||
typedef agg::path_storage AGGPath;
|
||||
typedef agg::conv_curve<AGGPath> AGGCurvedPath;
|
||||
|
||||
class PathSource : public VertexSource {
|
||||
public:
|
||||
PathSource(PathContainer* paths);
|
||||
virtual ~PathSource();
|
||||
|
||||
virtual void rewind(unsigned path_id);
|
||||
virtual unsigned vertex(double* x, double* y);
|
||||
|
||||
virtual bool WantsOpenPaths() const;
|
||||
virtual double ApproximationScale() const;
|
||||
|
||||
// PathSource
|
||||
void Update(bool leavePathsOpen,
|
||||
double approximationScale);
|
||||
|
||||
private:
|
||||
PathContainer* fPaths;
|
||||
AGGPath fAGGPath;
|
||||
AGGCurvedPath fAGGCurvedPath;
|
||||
};
|
||||
|
||||
#endif // PATH_SOURCE_H
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "PerspectiveTransformer.h"
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
# include <Message.h>
|
||||
#endif
|
||||
|
||||
#include <new>
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// constructor
|
||||
PerspectiveTransformer::PerspectiveTransformer(VertexSource& source)
|
||||
: Transformer(source, "Perspective"),
|
||||
Perspective(source, *this)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// constructor
|
||||
PerspectiveTransformer::PerspectiveTransformer(VertexSource& source,
|
||||
BMessage* archive)
|
||||
: Transformer(source, archive),
|
||||
Perspective(source, *this)
|
||||
{
|
||||
// TODO: upgrade AGG to be able to use load_from() etc
|
||||
}
|
||||
#endif
|
||||
|
||||
// destructor
|
||||
PerspectiveTransformer::~PerspectiveTransformer()
|
||||
{
|
||||
}
|
||||
|
||||
// Clone
|
||||
Transformer*
|
||||
PerspectiveTransformer::Clone(VertexSource& source) const
|
||||
{
|
||||
PerspectiveTransformer* clone
|
||||
= new (nothrow) PerspectiveTransformer(source);
|
||||
if (clone) {
|
||||
// TODO: upgrade AGG
|
||||
// clone->multiply(*this);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
// rewind
|
||||
void
|
||||
PerspectiveTransformer::rewind(unsigned path_id)
|
||||
{
|
||||
Perspective::rewind(path_id);
|
||||
}
|
||||
|
||||
// vertex
|
||||
unsigned
|
||||
PerspectiveTransformer::vertex(double* x, double* y)
|
||||
{
|
||||
return Perspective::vertex(x, y);
|
||||
}
|
||||
|
||||
// SetSource
|
||||
void
|
||||
PerspectiveTransformer::SetSource(VertexSource& source)
|
||||
{
|
||||
Transformer::SetSource(source);
|
||||
Perspective::attach(source);
|
||||
}
|
||||
|
||||
// ApproximationScale
|
||||
double
|
||||
PerspectiveTransformer::ApproximationScale() const
|
||||
{
|
||||
// TODO: upgrade AGG
|
||||
return fSource.ApproximationScale();// * scale();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
|
||||
// Archive
|
||||
status_t
|
||||
PerspectiveTransformer::Archive(BMessage* into, bool deep) const
|
||||
{
|
||||
status_t ret = Transformer::Archive(into, deep);
|
||||
|
||||
if (ret == B_OK)
|
||||
into->what = archive_code;
|
||||
|
||||
// TODO: upgrade AGG to be able to use store_to()
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef PERSPECTIVE_TRANSFORMER_H
|
||||
#define PERSPECTIVE_TRANSFORMER_H
|
||||
|
||||
#include <agg_conv_transform.h>
|
||||
#include <agg_trans_perspective.h>
|
||||
|
||||
#include "Transformer.h"
|
||||
|
||||
typedef agg::conv_transform<VertexSource,
|
||||
agg::trans_perspective> Perspective;
|
||||
|
||||
class PerspectiveTransformer : public Transformer,
|
||||
public Perspective,
|
||||
public agg::trans_perspective {
|
||||
public:
|
||||
enum {
|
||||
archive_code = 'prsp',
|
||||
};
|
||||
|
||||
PerspectiveTransformer(
|
||||
VertexSource& source);
|
||||
#ifdef ICON_O_MATIC
|
||||
PerspectiveTransformer(
|
||||
VertexSource& source,
|
||||
BMessage* archive);
|
||||
#endif
|
||||
virtual ~PerspectiveTransformer();
|
||||
|
||||
// Transformer interface
|
||||
virtual Transformer* Clone(VertexSource& source) const;
|
||||
|
||||
virtual void rewind(unsigned path_id);
|
||||
virtual unsigned vertex(double* x, double* y);
|
||||
|
||||
virtual void SetSource(VertexSource& source);
|
||||
|
||||
virtual double ApproximationScale() const;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// IconObject interface
|
||||
virtual status_t Archive(BMessage* into,
|
||||
bool deep = true) const;
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // PERSPECTIVE_TRANSFORMER_H
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "StrokeTransformer.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
# include <Message.h>
|
||||
|
||||
# include "CommonPropertyIDs.h"
|
||||
# include "OptionProperty.h"
|
||||
# include "Property.h"
|
||||
# include "PropertyObject.h"
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// constructor
|
||||
StrokeTransformer::StrokeTransformer(VertexSource& source)
|
||||
: Transformer(source, "Stroke"),
|
||||
Stroke(source)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// constructor
|
||||
StrokeTransformer::StrokeTransformer(VertexSource& source,
|
||||
BMessage* archive)
|
||||
: Transformer(source, archive),
|
||||
Stroke(source)
|
||||
{
|
||||
if (!archive)
|
||||
return;
|
||||
|
||||
int32 mode;
|
||||
if (archive->FindInt32("line cap", &mode) == B_OK)
|
||||
line_cap((agg::line_cap_e)mode);
|
||||
|
||||
if (archive->FindInt32("line join", &mode) == B_OK)
|
||||
line_join((agg::line_join_e)mode);
|
||||
|
||||
if (archive->FindInt32("inner join", &mode) == B_OK)
|
||||
inner_join((agg::inner_join_e)mode);
|
||||
|
||||
double value;
|
||||
if (archive->FindDouble("width", &value) == B_OK)
|
||||
width(value);
|
||||
|
||||
if (archive->FindDouble("miter limit", &value) == B_OK)
|
||||
miter_limit(value);
|
||||
|
||||
if (archive->FindDouble("inner miter limit", &value) == B_OK)
|
||||
inner_miter_limit(value);
|
||||
|
||||
if (archive->FindDouble("shorten", &value) == B_OK)
|
||||
shorten(value);
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
// destructor
|
||||
StrokeTransformer::~StrokeTransformer()
|
||||
{
|
||||
}
|
||||
|
||||
// Clone
|
||||
Transformer*
|
||||
StrokeTransformer::Clone(VertexSource& source) const
|
||||
{
|
||||
StrokeTransformer* clone = new (nothrow) StrokeTransformer(source);
|
||||
if (clone) {
|
||||
clone->line_cap(line_cap());
|
||||
clone->line_join(line_join());
|
||||
clone->inner_join(inner_join());
|
||||
clone->width(width());
|
||||
clone->miter_limit(miter_limit());
|
||||
clone->inner_miter_limit(inner_miter_limit());
|
||||
clone->shorten(shorten());
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
// rewind
|
||||
void
|
||||
StrokeTransformer::rewind(unsigned path_id)
|
||||
{
|
||||
Stroke::rewind(path_id);
|
||||
}
|
||||
|
||||
// vertex
|
||||
unsigned
|
||||
StrokeTransformer::vertex(double* x, double* y)
|
||||
{
|
||||
return Stroke::vertex(x, y);
|
||||
}
|
||||
|
||||
// SetSource
|
||||
void
|
||||
StrokeTransformer::SetSource(VertexSource& source)
|
||||
{
|
||||
Transformer::SetSource(source);
|
||||
Stroke::attach(source);
|
||||
}
|
||||
|
||||
// WantsOpenPaths
|
||||
bool
|
||||
StrokeTransformer::WantsOpenPaths() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// ApproximationScale
|
||||
double
|
||||
StrokeTransformer::ApproximationScale() const
|
||||
{
|
||||
return fSource.ApproximationScale() * width();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
|
||||
// Archive
|
||||
status_t
|
||||
StrokeTransformer::Archive(BMessage* into, bool deep) const
|
||||
{
|
||||
status_t ret = Transformer::Archive(into, deep);
|
||||
|
||||
if (ret == B_OK)
|
||||
into->what = archive_code;
|
||||
|
||||
if (ret == B_OK)
|
||||
ret = into->AddInt32("line cap", line_cap());
|
||||
|
||||
if (ret == B_OK)
|
||||
ret = into->AddInt32("line join", line_join());
|
||||
|
||||
if (ret == B_OK)
|
||||
ret = into->AddInt32("inner join", inner_join());
|
||||
|
||||
if (ret == B_OK)
|
||||
ret = into->AddDouble("width", width());
|
||||
|
||||
if (ret == B_OK)
|
||||
ret = into->AddDouble("miter limit", miter_limit());
|
||||
|
||||
if (ret == B_OK)
|
||||
ret = into->AddDouble("inner miter limit", inner_miter_limit());
|
||||
|
||||
if (ret == B_OK)
|
||||
ret = into->AddDouble("shorten",shorten());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// MakePropertyObject
|
||||
PropertyObject*
|
||||
StrokeTransformer::MakePropertyObject() const
|
||||
{
|
||||
PropertyObject* object = Transformer::MakePropertyObject();
|
||||
if (!object)
|
||||
return NULL;
|
||||
|
||||
// width
|
||||
object->AddProperty(new FloatProperty(PROPERTY_WIDTH, width()));
|
||||
|
||||
// cap mode
|
||||
OptionProperty* property = new OptionProperty(PROPERTY_CAP_MODE);
|
||||
property->AddOption(agg::butt_cap, "Butt");
|
||||
property->AddOption(agg::square_cap, "Square");
|
||||
property->AddOption(agg::round_cap, "Round");
|
||||
property->SetCurrentOptionID(line_cap());
|
||||
|
||||
object->AddProperty(property);
|
||||
|
||||
// join mode
|
||||
property = new OptionProperty(PROPERTY_JOIN_MODE);
|
||||
property->AddOption(agg::miter_join, "Miter");
|
||||
property->AddOption(agg::round_join, "Round");
|
||||
property->AddOption(agg::bevel_join, "Bevel");
|
||||
property->SetCurrentOptionID(line_join());
|
||||
|
||||
object->AddProperty(property);
|
||||
|
||||
// miter limit
|
||||
if (line_join() == agg::miter_join) {
|
||||
object->AddProperty(new FloatProperty(PROPERTY_MITER_LIMIT,
|
||||
miter_limit()));
|
||||
}
|
||||
|
||||
// shorten
|
||||
object->AddProperty(new FloatProperty(PROPERTY_STROKE_SHORTEN,
|
||||
shorten()));
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
// SetToPropertyObject
|
||||
bool
|
||||
StrokeTransformer::SetToPropertyObject(const PropertyObject* object)
|
||||
{
|
||||
AutoNotificationSuspender _(this);
|
||||
Transformer::SetToPropertyObject(object);
|
||||
|
||||
// width
|
||||
float w = object->Value(PROPERTY_WIDTH, (float)width());
|
||||
if (w != width()) {
|
||||
width(w);
|
||||
Notify();
|
||||
}
|
||||
|
||||
// cap mode
|
||||
OptionProperty* property = dynamic_cast<OptionProperty*>(
|
||||
object->FindProperty(PROPERTY_CAP_MODE));
|
||||
if (property && line_cap() != property->CurrentOptionID()) {
|
||||
line_cap((agg::line_cap_e)property->CurrentOptionID());
|
||||
Notify();
|
||||
}
|
||||
// join mode
|
||||
property = dynamic_cast<OptionProperty*>(
|
||||
object->FindProperty(PROPERTY_JOIN_MODE));
|
||||
if (property && line_join() != property->CurrentOptionID()) {
|
||||
line_join((agg::line_join_e)property->CurrentOptionID());
|
||||
Notify();
|
||||
}
|
||||
|
||||
// miter limit
|
||||
float l = object->Value(PROPERTY_MITER_LIMIT, (float)miter_limit());
|
||||
if (l != miter_limit()) {
|
||||
miter_limit(l);
|
||||
Notify();
|
||||
}
|
||||
|
||||
// shorten
|
||||
float s = object->Value(PROPERTY_STROKE_SHORTEN, (float)shorten());
|
||||
if (s != shorten()) {
|
||||
shorten(s);
|
||||
Notify();
|
||||
}
|
||||
|
||||
return HasPendingNotifications();
|
||||
}
|
||||
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef STROKE_TRANSFORMER_H
|
||||
#define STROKE_TRANSFORMER_H
|
||||
|
||||
#include <agg_conv_stroke.h>
|
||||
|
||||
#include "Transformer.h"
|
||||
|
||||
typedef agg::conv_stroke<VertexSource> Stroke;
|
||||
|
||||
class StrokeTransformer : public Transformer,
|
||||
public Stroke {
|
||||
public:
|
||||
enum {
|
||||
archive_code = 'strk',
|
||||
};
|
||||
|
||||
StrokeTransformer(
|
||||
VertexSource& source);
|
||||
#ifdef ICON_O_MATIC
|
||||
StrokeTransformer(
|
||||
VertexSource& source,
|
||||
BMessage* archive);
|
||||
#endif
|
||||
virtual ~StrokeTransformer();
|
||||
|
||||
// Transformer interface
|
||||
virtual Transformer* Clone(VertexSource& source) const;
|
||||
|
||||
virtual void rewind(unsigned path_id);
|
||||
virtual unsigned vertex(double* x, double* y);
|
||||
|
||||
virtual void SetSource(VertexSource& source);
|
||||
|
||||
virtual bool WantsOpenPaths() const;
|
||||
virtual double ApproximationScale() const;
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// IconObject interface
|
||||
virtual status_t Archive(BMessage* into,
|
||||
bool deep = true) const;
|
||||
|
||||
virtual PropertyObject* MakePropertyObject() const;
|
||||
virtual bool SetToPropertyObject(
|
||||
const PropertyObject* object);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // STROKE_TRANSFORMER_H
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Transformer.h"
|
||||
|
||||
// constructor
|
||||
VertexSource::VertexSource()
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
VertexSource::~VertexSource()
|
||||
{
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
Transformer::Transformer(VertexSource& source, const char* name)
|
||||
#ifdef ICON_O_MATIC
|
||||
: IconObject(name),
|
||||
#else
|
||||
:
|
||||
#endif
|
||||
fSource(source)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// constructor
|
||||
Transformer::Transformer(VertexSource& source,
|
||||
BMessage* archive)
|
||||
: IconObject(archive),
|
||||
fSource(source)
|
||||
{
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
|
||||
// destructor
|
||||
Transformer::~Transformer()
|
||||
{
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// rewind
|
||||
void
|
||||
Transformer::rewind(unsigned path_id)
|
||||
{
|
||||
fSource.rewind(path_id);
|
||||
}
|
||||
|
||||
// vertex
|
||||
unsigned
|
||||
Transformer::vertex(double* x, double* y)
|
||||
{
|
||||
return fSource.vertex(x, y);
|
||||
}
|
||||
|
||||
// SetSource
|
||||
void
|
||||
Transformer::SetSource(VertexSource& source)
|
||||
{
|
||||
fSource = source;
|
||||
}
|
||||
|
||||
// WantsOpenPaths
|
||||
bool
|
||||
Transformer::WantsOpenPaths() const
|
||||
{
|
||||
return fSource.WantsOpenPaths();
|
||||
}
|
||||
|
||||
// ApproximationScale
|
||||
double
|
||||
Transformer::ApproximationScale() const
|
||||
{
|
||||
return fSource.ApproximationScale();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef TRANSFORMER_H
|
||||
#define TRANSFORMER_H
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
# include "IconObject.h"
|
||||
#else
|
||||
# include <SupportDefs.h>
|
||||
#endif
|
||||
|
||||
class VertexSource {
|
||||
public:
|
||||
VertexSource();
|
||||
virtual ~VertexSource();
|
||||
|
||||
virtual void rewind(unsigned path_id) = 0;
|
||||
virtual unsigned vertex(double* x, double* y) = 0;
|
||||
|
||||
virtual bool WantsOpenPaths() const = 0;
|
||||
virtual double ApproximationScale() const = 0;
|
||||
};
|
||||
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
class Transformer : public VertexSource,
|
||||
public IconObject {
|
||||
#else
|
||||
class Transformer : public VertexSource {
|
||||
#endif
|
||||
public:
|
||||
Transformer(VertexSource& source,
|
||||
const char* name);
|
||||
#ifdef ICON_O_MATIC
|
||||
Transformer(VertexSource& source,
|
||||
BMessage* archive);
|
||||
#endif
|
||||
virtual ~Transformer();
|
||||
|
||||
// Transformer
|
||||
virtual Transformer* Clone(VertexSource& source) const = 0;
|
||||
|
||||
virtual void rewind(unsigned path_id);
|
||||
virtual unsigned vertex(double* x, double* y);
|
||||
|
||||
virtual void SetSource(VertexSource& source);
|
||||
|
||||
virtual bool WantsOpenPaths() const;
|
||||
virtual double ApproximationScale() const;
|
||||
|
||||
protected:
|
||||
VertexSource& fSource;
|
||||
};
|
||||
|
||||
#endif // TRANSFORMER_H
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "TransformerFactory.h"
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
# include <Message.h>
|
||||
#endif
|
||||
|
||||
#include "AffineTransformer.h"
|
||||
#include "ContourTransformer.h"
|
||||
#include "PerspectiveTransformer.h"
|
||||
#include "StrokeTransformer.h"
|
||||
|
||||
// TransformerFor
|
||||
Transformer*
|
||||
TransformerFactory::TransformerFor(uint32 type, VertexSource& source)
|
||||
{
|
||||
switch (type) {
|
||||
case 0:
|
||||
return new AffineTransformer(source);
|
||||
case 1:
|
||||
return new PerspectiveTransformer(source);
|
||||
case 2:
|
||||
return new ContourTransformer(source);
|
||||
case 3:
|
||||
return new StrokeTransformer(source);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
// TransformerFor
|
||||
Transformer*
|
||||
TransformerFactory::TransformerFor(BMessage* message,
|
||||
VertexSource& source)
|
||||
{
|
||||
switch (message->what) {
|
||||
case AffineTransformer::archive_code:
|
||||
return new AffineTransformer(source, message);
|
||||
case PerspectiveTransformer::archive_code:
|
||||
return new PerspectiveTransformer(source, message);
|
||||
case ContourTransformer::archive_code:
|
||||
return new ContourTransformer(source, message);
|
||||
case StrokeTransformer::archive_code:
|
||||
return new StrokeTransformer(source, message);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// NextType
|
||||
bool
|
||||
TransformerFactory::NextType(int32* cookie, uint32* type, BString* name)
|
||||
{
|
||||
*type = *cookie;
|
||||
*cookie = *cookie + 1;
|
||||
|
||||
switch (*type) {
|
||||
case 0:
|
||||
*name = "Transformation";
|
||||
return true;
|
||||
case 1:
|
||||
*name = "Perspective";
|
||||
return true;
|
||||
case 2:
|
||||
*name = "Contour";
|
||||
return true;
|
||||
case 3:
|
||||
*name = "Stroke";
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif // ICON_O_MATIC
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef TRANSFORMER_FACTORY_H
|
||||
#define TRANSFORMER_FACTORY_H
|
||||
|
||||
#include <String.h>
|
||||
|
||||
class BMessage;
|
||||
class Transformer;
|
||||
class VertexSource;
|
||||
|
||||
class TransformerFactory {
|
||||
public:
|
||||
|
||||
static Transformer* TransformerFor(uint32 type,
|
||||
VertexSource& source);
|
||||
|
||||
#ifdef ICON_O_MATIC
|
||||
static Transformer* TransformerFor(BMessage* archive,
|
||||
VertexSource& source);
|
||||
|
||||
static bool NextType(int32* cookie,
|
||||
uint32* type,
|
||||
BString* name);
|
||||
|
||||
#endif // ICON_O_MATIC
|
||||
};
|
||||
|
||||
#endif // TRANSFORMER_FACTORY_H
|
||||
Reference in New Issue
Block a user