diff --git a/headers/libs/agg/agg_trans_perspective.h b/headers/libs/agg/agg_trans_perspective.h index 1c650aac8d..b7979e1272 100644 --- a/headers/libs/agg/agg_trans_perspective.h +++ b/headers/libs/agg/agg_trans_perspective.h @@ -502,7 +502,7 @@ namespace agg } //------------------------------------------------------------------------ - const trans_perspective& + inline const trans_perspective& trans_perspective::multiply_inv(const trans_perspective& m) { trans_perspective t = m; @@ -511,7 +511,7 @@ namespace agg } //------------------------------------------------------------------------ - const trans_perspective& + inline const trans_perspective& trans_perspective::multiply_inv(const trans_affine& m) { trans_affine t = m; @@ -520,7 +520,7 @@ namespace agg } //------------------------------------------------------------------------ - const trans_perspective& + inline const trans_perspective& trans_perspective::premultiply_inv(const trans_perspective& m) { trans_perspective t = m; @@ -529,7 +529,7 @@ namespace agg } //------------------------------------------------------------------------ - const trans_perspective& + inline const trans_perspective& trans_perspective::premultiply_inv(const trans_affine& m) { trans_perspective t(m); @@ -697,14 +697,14 @@ namespace agg } //------------------------------------------------------------------------ - void trans_perspective::translation(double* dx, double* dy) const + inline void trans_perspective::translation(double* dx, double* dy) const { *dx = tx; *dy = ty; } //------------------------------------------------------------------------ - void trans_perspective::scaling(double* x, double* y) const + inline void trans_perspective::scaling(double* x, double* y) const { double x1 = 0.0; double y1 = 0.0; @@ -719,7 +719,7 @@ namespace agg } //------------------------------------------------------------------------ - void trans_perspective::scaling_abs(double* x, double* y) const + inline void trans_perspective::scaling_abs(double* x, double* y) const { *x = std::sqrt(sx * sx + shx * shx); *y = std::sqrt(shy * shy + sy * sy); diff --git a/src/apps/icon-o-matic/Jamfile b/src/apps/icon-o-matic/Jamfile index 2334f8a86e..bf167a638a 100644 --- a/src/apps/icon-o-matic/Jamfile +++ b/src/apps/icon-o-matic/Jamfile @@ -95,11 +95,12 @@ Application Icon-O-Matic : # icon/transformer AffineTransformer.cpp + CompoundStyleTransformer.cpp ContourTransformer.cpp PathSource.cpp PerspectiveTransformer.cpp StrokeTransformer.cpp - Transformer.cpp + StyleTransformer.cpp TransformerFactory.cpp # icon @@ -275,6 +276,9 @@ Application Icon-O-Matic : # transformable CanvasTransformBox.cpp ChannelTransform.cpp + PerspectiveBox.cpp + PerspectiveBoxStates.cpp + PerspectiveCommand.cpp ResetTransformationCommand.cpp TransformBox.cpp TransformBoxStates.cpp @@ -349,6 +353,7 @@ DoCatalogs Icon-O-Matic : RemoveStylesCommand.cpp SetColorCommand.cpp SetGradientCommand.cpp + PerspectiveCommand.cpp ResetTransformationCommand.cpp TransformBoxStates.cpp TransformerFactory.cpp diff --git a/src/apps/icon-o-matic/MainWindow.cpp b/src/apps/icon-o-matic/MainWindow.cpp index ac4bfa9765..99425cf27e 100644 --- a/src/apps/icon-o-matic/MainWindow.cpp +++ b/src/apps/icon-o-matic/MainWindow.cpp @@ -59,6 +59,8 @@ #include "MessengerSaver.h" #include "NativeSaver.h" #include "PathListView.h" +#include "PerspectiveBox.h" +#include "PerspectiveTransformer.h" #include "RDefExporter.h" #include "ScrollView.h" #include "SimpleFileSaver.h" @@ -105,6 +107,7 @@ enum { MSG_PATH_SELECTED = 'vpsl', MSG_STYLE_SELECTED = 'stsl', MSG_SHAPE_SELECTED = 'spsl', + MSG_TRANSFORMER_SELECTED = 'trsl', MSG_SHAPE_RESET_TRANSFORMATION = 'rtsh', MSG_STYLE_RESET_TRANSFORMATION = 'rtst', @@ -562,6 +565,20 @@ case MSG_SHAPE_SELECTED: { fState->AddManipulator(transformBox); } break; +} +case MSG_TRANSFORMER_SELECTED: { + Transformer* transformer; + if (message->FindPointer("transformer", (void**)&transformer) < B_OK) + transformer = NULL; + + fState->DeleteManipulators(); + PerspectiveTransformer* perspectiveTransformer = + dynamic_cast(transformer); + if (perspectiveTransformer != NULL) { + PerspectiveBox* transformBox = new (nothrow) PerspectiveBox( + fCanvasView, perspectiveTransformer); + fState->AddManipulator(transformBox); + } } case MSG_RENAME_OBJECT: fPropertyListView->FocusNameProperty(); @@ -1087,7 +1104,7 @@ MainWindow::_CreateGUI() fShapeListView = new ShapeListView(BRect(0, 0, splitWidth, 100), "shape list view", new BMessage(MSG_SHAPE_SELECTED), this); fTransformerListView = new TransformerListView(BRect(0, 0, splitWidth, 100), - "transformer list view"); + "transformer list view", new BMessage(MSG_TRANSFORMER_SELECTED), this); fPropertyListView = new IconObjectListView(); BLayoutBuilder::Split<>(leftSideView) diff --git a/src/apps/icon-o-matic/document/IconObject.h b/src/apps/icon-o-matic/document/IconObject.h index 0a29412473..1fb25b32eb 100644 --- a/src/apps/icon-o-matic/document/IconObject.h +++ b/src/apps/icon-o-matic/document/IconObject.h @@ -43,6 +43,9 @@ class IconObject : public Observable, const char* Name() const { return fName.String(); } + // TODO: let IconObject control its own manipulators? + // This would allow VectorPaths to control their own PathManipulator, + // Styles to control their own TransformGradientBox, etc. private: BString fName; }; diff --git a/src/apps/icon-o-matic/gui/TransformerListView.cpp b/src/apps/icon-o-matic/gui/TransformerListView.cpp index cd1373f5e0..ebd942f9fe 100644 --- a/src/apps/icon-o-matic/gui/TransformerListView.cpp +++ b/src/apps/icon-o-matic/gui/TransformerListView.cpp @@ -201,8 +201,7 @@ TransformerListView::MessageReceived(BMessage* message) break; Transformer* transformer - = TransformerFactory::TransformerFor(type, - fShape->VertexSource()); + = TransformerFactory::TransformerFor(type, fShape->VertexSource(), fShape); if (!transformer) break; @@ -396,9 +395,9 @@ TransformerListView::SetMenu(BMenu* menu) message->AddInt32("type", STROKE_TRANSFORMER); fStrokeMI = new BMenuItem(B_TRANSLATE("Stroke"), message); - // message = new BMessage(MSG_ADD_TRANSFORMER); - // message->AddInt32("type", PERSPECTIVE_TRANSFORMER); - // fPerspectiveMI = new BMenuItem(B_TRANSLATE("Perspective"), message); + message = new BMessage(MSG_ADD_TRANSFORMER); + message->AddInt32("type", PERSPECTIVE_TRANSFORMER); + fPerspectiveMI = new BMenuItem(B_TRANSLATE("Perspective"), message); // message = new BMessage(MSG_ADD_TRANSFORMER); // message->AddInt32("type", AFFINE_TRANSFORMER); @@ -408,6 +407,7 @@ TransformerListView::SetMenu(BMenu* menu) addMenu->AddItem(fContourMI); addMenu->AddItem(fStrokeMI); + addMenu->AddItem(fPerspectiveMI); addMenu->SetTargetForItems(this); fMenu->AddItem(addMenu); diff --git a/src/apps/icon-o-matic/gui/TransformerListView.h b/src/apps/icon-o-matic/gui/TransformerListView.h index e547e7bc86..1db4302343 100644 --- a/src/apps/icon-o-matic/gui/TransformerListView.h +++ b/src/apps/icon-o-matic/gui/TransformerListView.h @@ -82,6 +82,7 @@ class TransformerListView : public SimpleListView, BMenu* fMenu; BMenuItem* fContourMI; BMenuItem* fStrokeMI; + BMenuItem* fPerspectiveMI; }; #endif // TRANSFORMER_LIST_VIEW_H diff --git a/src/apps/icon-o-matic/import_export/flat_icon/FlatIconExporter.cpp b/src/apps/icon-o-matic/import_export/flat_icon/FlatIconExporter.cpp index 31d2e78068..0842d1f6e2 100644 --- a/src/apps/icon-o-matic/import_export/flat_icon/FlatIconExporter.cpp +++ b/src/apps/icon-o-matic/import_export/flat_icon/FlatIconExporter.cpp @@ -483,11 +483,17 @@ _WriteTransformer(LittleEndianBuffer& buffer, Transformer* t) || !buffer.Write(miterLimit)) return false; - } else if (dynamic_cast(t)) { + } else if (PerspectiveTransformer* perspective + = dynamic_cast(t)) { // perspective if (!buffer.Write((uint8)TRANSFORMER_TYPE_PERSPECTIVE)) return false; - // TODO: ... (upgrade AGG for storage support of trans_perspective) + double matrix[9]; + perspective->store_to(matrix); + for (int32 i = 0; i < 9; i++) { + if (!write_float_24(buffer, (float)matrix[i])) + return false; + } } else if (StrokeTransformer* stroke = dynamic_cast(t)) { diff --git a/src/apps/icon-o-matic/import_export/styled_text/StyledTextImporter.h b/src/apps/icon-o-matic/import_export/styled_text/StyledTextImporter.h index 7fb5b8cdb3..702c4667d8 100644 --- a/src/apps/icon-o-matic/import_export/styled_text/StyledTextImporter.h +++ b/src/apps/icon-o-matic/import_export/styled_text/StyledTextImporter.h @@ -29,7 +29,7 @@ struct style_map { /*! Turns text into its associated paths and shapes. Coloring can also be imported from applications, such as StyledEdit, that - specify it. + specify it in a supported format. */ class StyledTextImporter : public Importer { public: diff --git a/src/apps/icon-o-matic/transformable/PerspectiveBox.cpp b/src/apps/icon-o-matic/transformable/PerspectiveBox.cpp new file mode 100644 index 0000000000..f63c5789e8 --- /dev/null +++ b/src/apps/icon-o-matic/transformable/PerspectiveBox.cpp @@ -0,0 +1,449 @@ +/* + * Copyright 2006-2009, 2023, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + * Zardshard + */ + +#include "PerspectiveBox.h" + +#include + +#include +#include + +#include + +#include "CanvasView.h" +#include "StateView.h" +#include "support.h" +#include "PerspectiveBoxStates.h" +#include "PerspectiveCommand.h" +#include "PerspectiveTransformer.h" + + +#define INSET 8.0 + + +using std::nothrow; +using namespace PerspectiveBoxStates; + + +PerspectiveBox::PerspectiveBox(CanvasView* view, + PerspectiveTransformer* parent) + : + Manipulator(NULL), + + fLeftTop(parent->LeftTop()), + fRightTop(parent->RightTop()), + fLeftBottom(parent->LeftBottom()), + fRightBottom(parent->RightBottom()), + + fCurrentCommand(NULL), + fCurrentState(NULL), + + fDragging(false), + fMousePos(-10000.0, -10000.0), + fModifiers(0), + + fPreviousBox(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN), + + fCanvasView(view), + fPerspective(parent), + + fDragLTState(new DragCornerState(this, &fLeftTop)), + fDragRTState(new DragCornerState(this, &fRightTop)), + fDragLBState(new DragCornerState(this, &fLeftBottom)), + fDragRBState(new DragCornerState(this, &fRightBottom)) +{ +} + + +PerspectiveBox::~PerspectiveBox() +{ + _NotifyDeleted(); + + delete fCurrentCommand; + delete fDragLTState; + delete fDragRTState; + delete fDragLBState; + delete fDragRBState; +} + + +void +PerspectiveBox::Draw(BView* into, BRect updateRect) +{ + // convert to canvas view coordinates + BPoint lt = fLeftTop; + BPoint rt = fRightTop; + BPoint lb = fLeftBottom; + BPoint rb = fRightBottom; + + fCanvasView->ConvertFromCanvas(<); + fCanvasView->ConvertFromCanvas(&rt); + fCanvasView->ConvertFromCanvas(&lb); + fCanvasView->ConvertFromCanvas(&rb); + + into->SetDrawingMode(B_OP_COPY); + into->SetHighColor(255, 255, 255, 255); + into->SetLowColor(0, 0, 0, 255); + + _StrokeBWLine(into, lt, rt); + _StrokeBWLine(into, rt, rb); + _StrokeBWLine(into, rb, lb); + _StrokeBWLine(into, lb, lt); + + _StrokeBWPoint(into, lt, 0.0); + _StrokeBWPoint(into, rt, 90.0); + _StrokeBWPoint(into, rb, 180.0); + _StrokeBWPoint(into, lb, 270.0); +} + + +// #pragma mark - + + +bool +PerspectiveBox::MouseDown(BPoint where) +{ + fCanvasView->FilterMouse(&where); + fCanvasView->ConvertToCanvas(&where); + + fDragging = true; + if (fCurrentState) { + fCurrentState->SetOrigin(where); + + delete fCurrentCommand; + fCurrentCommand = new (nothrow) PerspectiveCommand(this, fPerspective, + fPerspective->LeftTop(), fPerspective->RightTop(), + fPerspective->LeftBottom(), fPerspective->RightBottom()); + } + + return true; +} + + +void +PerspectiveBox::MouseMoved(BPoint where) +{ + fCanvasView->FilterMouse(&where); + fCanvasView->ConvertToCanvas(&where); + + if (fMousePos != where) { + fMousePos = where; + if (fCurrentState) { + fCurrentState->DragTo(fMousePos, fModifiers); + fCurrentState->UpdateViewCursor(fCanvasView, fMousePos); + } + } +} + + +Command* +PerspectiveBox::MouseUp() +{ + fDragging = false; + return FinishTransaction(); +} + + +bool +PerspectiveBox::MouseOver(BPoint where) +{ + fCanvasView->ConvertToCanvas(&where); + + fMousePos = where; + fCurrentState = _DragStateFor(where, fCanvasView->ZoomLevel()); + + if (fCurrentState) { + fCurrentState->UpdateViewCursor(fCanvasView, fMousePos); + return true; + } + + return false; +} + + +// #pragma mark - + + +BRect +PerspectiveBox::Bounds() +{ + // convert from canvas view coordinates + BPoint lt = fLeftTop; + BPoint rt = fRightTop; + BPoint lb = fLeftBottom; + BPoint rb = fRightBottom; + + fCanvasView->ConvertFromCanvas(<); + fCanvasView->ConvertFromCanvas(&rt); + fCanvasView->ConvertFromCanvas(&lb); + fCanvasView->ConvertFromCanvas(&rb); + + BRect bounds; + bounds.left = min4(lt.x, rt.x, lb.x, rb.x); + bounds.top = min4(lt.y, rt.y, lb.y, rb.y); + bounds.right = max4(lt.x, rt.x, lb.x, rb.x); + bounds.bottom = max4(lt.y, rt.y, lb.y, rb.y); + return bounds; +} + + +BRect +PerspectiveBox::TrackingBounds(BView* withinView) +{ + return withinView->Bounds(); +} + + +// #pragma mark - + + +void +PerspectiveBox::ModifiersChanged(uint32 modifiers) +{ + fModifiers = modifiers; + if (fDragging && fCurrentState) { + fCurrentState->DragTo(fMousePos, fModifiers); + } +} + + +bool +PerspectiveBox::UpdateCursor() +{ + if (fCurrentState) { + fCurrentState->UpdateViewCursor(fCanvasView, fMousePos); + return true; + } + return false; +} + + +// #pragma mark - + + +void +PerspectiveBox::AttachedToView(BView* view) +{ + view->Invalidate(Bounds().InsetByCopy(-INSET, -INSET)); +} + + +void +PerspectiveBox::DetachedFromView(BView* view) +{ + view->Invalidate(Bounds().InsetByCopy(-INSET, -INSET)); +} + + +// pragma mark - + + +void +PerspectiveBox::ObjectChanged(const Observable* object) +{ +} + + +// pragma mark - + + +void +PerspectiveBox::TransformTo( + BPoint leftTop, BPoint rightTop, BPoint leftBottom, BPoint rightBottom) +{ + if (fLeftTop == leftTop + && fRightTop == rightTop + && fLeftBottom == leftBottom + && fRightBottom == rightBottom) + return; + + fLeftTop = leftTop; + fRightTop = rightTop; + fLeftBottom = leftBottom; + fRightBottom = rightBottom; + + Update(); +} + + +void +PerspectiveBox::Update(bool deep) +{ + BRect r = Bounds(); + BRect dirty(r | fPreviousBox); + dirty.InsetBy(-INSET, -INSET); + fCanvasView->Invalidate(dirty); + fPreviousBox = r; + + if (deep) + fPerspective->TransformTo(fLeftTop, fRightTop, fLeftBottom, fRightBottom); +} + + +Command* +PerspectiveBox::FinishTransaction() +{ + Command* command = fCurrentCommand; + if (fCurrentCommand) { + fCurrentCommand->SetNewPerspective( + fPerspective->LeftTop(), fPerspective->RightTop(), + fPerspective->LeftBottom(), fPerspective->RightBottom()); + fCurrentCommand = NULL; + } + return command; +} + + +// #pragma mark - + + +bool +PerspectiveBox::AddListener(PerspectiveBoxListener* listener) +{ + if (listener && !fListeners.HasItem((void*)listener)) + return fListeners.AddItem((void*)listener); + return false; +} + + +bool +PerspectiveBox::RemoveListener(PerspectiveBoxListener* listener) +{ + return fListeners.RemoveItem((void*)listener); +} + + +// #pragma mark - + + +void +PerspectiveBox::_NotifyDeleted() const +{ + BList listeners(fListeners); + int32 count = listeners.CountItems(); + for (int32 i = 0; i < count; i++) { + PerspectiveBoxListener* listener + = (PerspectiveBoxListener*)listeners.ItemAtFast(i); + listener->PerspectiveBoxDeleted(this); + } +} + + +//! where is expected in canvas view coordinates +DragState* +PerspectiveBox::_DragStateFor(BPoint where, float canvasZoom) +{ + DragState* state = NULL; + + // convert to canvas zoom level + // + // the conversion is necessary, because the "hot regions" + // around a point should be the same size no matter what + // zoom level the canvas is displayed at + float inset = INSET / canvasZoom; + + // check if the cursor is over the corners + float dLT = point_point_distance(fLeftTop, where); + float dRT = point_point_distance(fRightTop, where); + float dLB = point_point_distance(fLeftBottom, where); + float dRB = point_point_distance(fRightBottom, where); + float d = min4(dLT, dRT, dLB, dRB); + if (d < inset) { + if (d == dLT) + state = fDragLTState; + else if (d == dRT) + state = fDragRTState; + else if (d == dLB) + state = fDragLBState; + else if (d == dRB) + state = fDragRBState; + } + + return state; +} + + +void +PerspectiveBox::_StrokeBWLine(BView* into, BPoint from, BPoint to) const +{ + // find out how to offset the second line optimally + BPoint offset(0.0, 0.0); + // first, do we have a more horizontal line or a more vertical line? + float xDiff = to.x - from.x; + float yDiff = to.y - from.y; + if (fabs(xDiff) > fabs(yDiff)) { + // horizontal + if (xDiff > 0.0) { + offset.y = -1.0; + } else { + offset.y = 1.0; + } + } else { + // vertical + if (yDiff < 0.0) { + offset.x = -1.0; + } else { + offset.x = 1.0; + } + } + // stroke two lines in high and low color of the view + into->StrokeLine(from, to, B_SOLID_LOW); + from += offset; + to += offset; + into->StrokeLine(from, to, B_SOLID_HIGH); +} + + +void +PerspectiveBox::_StrokeBWPoint(BView* into, BPoint point, double angle) const +{ + double x = point.x; + double y = point.y; + + double x1 = x; + double y1 = y - 5.0; + + double x2 = x - 5.0; + double y2 = y - 5.0; + + double x3 = x - 5.0; + double y3 = y; + + agg::trans_affine m; + + double xOffset = -x; + double yOffset = -y; + + agg::trans_affine_rotation r(angle * M_PI / 180.0); + + r.transform(&xOffset, &yOffset); + xOffset = x + xOffset; + yOffset = y + yOffset; + + m.multiply(r); + m.multiply(agg::trans_affine_translation(xOffset, yOffset)); + + m.transform(&x, &y); + m.transform(&x1, &y1); + m.transform(&x2, &y2); + m.transform(&x3, &y3); + + BPoint p[4]; + p[0] = BPoint(x, y); + p[1] = BPoint(x1, y1); + p[2] = BPoint(x2, y2); + p[3] = BPoint(x3, y3); + + into->FillPolygon(p, 4, B_SOLID_HIGH); + + into->StrokeLine(p[0], p[1], B_SOLID_LOW); + into->StrokeLine(p[1], p[2], B_SOLID_LOW); + into->StrokeLine(p[2], p[3], B_SOLID_LOW); + into->StrokeLine(p[3], p[0], B_SOLID_LOW); +} diff --git a/src/apps/icon-o-matic/transformable/PerspectiveBox.h b/src/apps/icon-o-matic/transformable/PerspectiveBox.h new file mode 100644 index 0000000000..929c601e6f --- /dev/null +++ b/src/apps/icon-o-matic/transformable/PerspectiveBox.h @@ -0,0 +1,115 @@ +/* + * Copyright 2006-2007, 2023, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + * Zardshard + */ +#ifndef PERSPECTIVE_BOX_H +#define PERSPECTIVE_BOX_H + +#include +#include +#include + +#include "Manipulator.h" + + +namespace PerspectiveBoxStates { + class DragState; +} + +class CanvasView; +class Command; +class PerspectiveCommand; +class PerspectiveBox; +class PerspectiveTransformer; + + +class PerspectiveBoxListener { +public: + PerspectiveBoxListener() {} + virtual ~PerspectiveBoxListener() {} + + virtual void PerspectiveBoxDeleted( + const PerspectiveBox* box) = 0; +}; + + +class PerspectiveBox : public Manipulator { +public: + PerspectiveBox(CanvasView* view, + PerspectiveTransformer* parent); + virtual ~PerspectiveBox(); + + // Manipulator interface + virtual void Draw(BView* into, BRect updateRect); + + virtual bool MouseDown(BPoint where); + virtual void MouseMoved(BPoint where); + virtual Command* MouseUp(); + virtual bool MouseOver(BPoint where); + + virtual BRect Bounds(); + virtual BRect TrackingBounds(BView* withinView); + + virtual void ModifiersChanged(uint32 modifiers); + + virtual bool UpdateCursor(); + + virtual void AttachedToView(BView* view); + virtual void DetachedFromView(BView* view); + + // Observer interface + virtual void ObjectChanged(const Observable* object); + + // PerspectiveTransformBox + void TransformTo(BPoint leftTop, BPoint rightTop, + BPoint leftBottom, BPoint rightBottom); + + virtual void Update(bool deep = true); + + Command* FinishTransaction(); + + // Listener support + bool AddListener(PerspectiveBoxListener* listener); + bool RemoveListener(PerspectiveBoxListener* listener); + +private: + void _NotifyDeleted() const; + PerspectiveBoxStates::DragState* _DragStateFor( + BPoint canvasWhere, float canvasZoom); + void _StrokeBWLine(BView* into, + BPoint from, BPoint to) const; + void _StrokeBWPoint(BView* into, + BPoint point, double angle) const; + +private: + BPoint fLeftTop; + BPoint fRightTop; + BPoint fLeftBottom; + BPoint fRightBottom; + + PerspectiveCommand* fCurrentCommand; + PerspectiveBoxStates::DragState* fCurrentState; + + bool fDragging; + BPoint fMousePos; + uint32 fModifiers; + + BList fListeners; + + BRect fPreviousBox; + + // "static" state objects + CanvasView* fCanvasView; + BReference fPerspective; + + PerspectiveBoxStates::DragState* fDragLTState; + PerspectiveBoxStates::DragState* fDragRTState; + PerspectiveBoxStates::DragState* fDragLBState; + PerspectiveBoxStates::DragState* fDragRBState; +}; + +#endif // PERSPECTIVE_BOX_H diff --git a/src/apps/icon-o-matic/transformable/PerspectiveBoxStates.cpp b/src/apps/icon-o-matic/transformable/PerspectiveBoxStates.cpp new file mode 100644 index 0000000000..3fd9a50b5c --- /dev/null +++ b/src/apps/icon-o-matic/transformable/PerspectiveBoxStates.cpp @@ -0,0 +1,68 @@ +/* + * Copyright 2006-2009, 2023, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + * Zardshard + */ + +#include "PerspectiveBoxStates.h" + +#include +#include + +#include "cursors.h" +#include "PerspectiveBox.h" + + +using namespace PerspectiveBoxStates; + + +DragState::DragState(PerspectiveBox* parent) + : + fOrigin(0.0, 0.0), + fParent(parent) +{ +} + + +void +DragState::_SetViewCursor(BView* view, const uchar* cursorData) const +{ + BCursor cursor(cursorData); + view->SetViewCursor(&cursor); +} + + +// #pragma mark - DragCornerState + + +DragCornerState::DragCornerState(PerspectiveBox* parent, BPoint* point) + : + DragState(parent), + fPoint(point) +{ +} + + +void +DragCornerState::SetOrigin(BPoint origin) +{ + DragState::SetOrigin(origin); +} + + +void +DragCornerState::DragTo(BPoint current, uint32 modifiers) +{ + *fPoint = current; + fParent->Update(true); +} + + +void +DragCornerState::UpdateViewCursor(BView* view, BPoint current) const +{ + _SetViewCursor(view, kPathMoveCursor); +} diff --git a/src/apps/icon-o-matic/transformable/PerspectiveBoxStates.h b/src/apps/icon-o-matic/transformable/PerspectiveBoxStates.h new file mode 100644 index 0000000000..090fa9e62b --- /dev/null +++ b/src/apps/icon-o-matic/transformable/PerspectiveBoxStates.h @@ -0,0 +1,58 @@ +/* + * Copyright 2006, 2023, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + * Zardshard + */ +#ifndef PERSPECTIVE_BOX_STATES_H +#define PERSPECTIVE_BOX_STATES_H + +#include + + +class BView; +class PerspectiveBox; + + +namespace PerspectiveBoxStates { + +class DragState { + public: + DragState(PerspectiveBox* parent); + virtual ~DragState() {} + + virtual void SetOrigin(BPoint origin) + { fOrigin = origin; } + virtual void DragTo(BPoint current, uint32 modifiers) = 0; + virtual void UpdateViewCursor(BView* view, BPoint current) const = 0; + + protected: + void _SetViewCursor(BView* view, + const uchar* cursorData) const; + + BPoint fOrigin; + PerspectiveBox* fParent; +}; + + +class DragCornerState : public DragState { + public: + DragCornerState( + PerspectiveBox* parent, BPoint* point); + virtual ~DragCornerState() {} + + virtual void SetOrigin(BPoint origin); + virtual void DragTo(BPoint current, uint32 modifiers); + virtual void UpdateViewCursor(BView* view, BPoint current) const; + + private: + BPoint* fPoint; + + BPoint fOldOffset; +}; + +} // PerspectiveBoxStates namespace + +#endif // PERSPECTIVE_BOX_STATES_H diff --git a/src/apps/icon-o-matic/transformable/PerspectiveCommand.cpp b/src/apps/icon-o-matic/transformable/PerspectiveCommand.cpp new file mode 100644 index 0000000000..d1de6b3561 --- /dev/null +++ b/src/apps/icon-o-matic/transformable/PerspectiveCommand.cpp @@ -0,0 +1,141 @@ +/* + * Copyright 2006-2010, Stephan Aßmus . + * Copyright 2006-2009, 2023, Haiku. + * All rights reserved. Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + * Zardshard + */ + + +#include "PerspectiveCommand.h" + +#include +#include + +#include "PerspectiveTransformer.h" + + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "Icon-O-Matic-PerspectiveCommand" + + +PerspectiveCommand::PerspectiveCommand(PerspectiveBox* box, + PerspectiveTransformer* transformer, BPoint leftTop, BPoint rightTop + , BPoint leftBottom, BPoint rightBottom) + : fTransformBox(box), + fTransformer(transformer), + fOldLeftTop(leftTop), + fOldRightTop(rightTop), + fOldLeftBottom(leftBottom), + fOldRightBottom(rightBottom), + fNewLeftTop(leftTop), + fNewRightTop(rightTop), + fNewLeftBottom(leftBottom), + fNewRightBottom(rightBottom) +{ + if (fTransformer == NULL) + return; + + fTransformer->AcquireReference(); + + if (fTransformBox != NULL) + fTransformBox->AddListener(this); +} + + +PerspectiveCommand::~PerspectiveCommand() +{ + if (fTransformer != NULL) + fTransformer->ReleaseReference(); + + if (fTransformBox != NULL) + fTransformBox->RemoveListener(this); +} + + +// pragma mark - + + +status_t +PerspectiveCommand::InitCheck() +{ + if (fTransformer != NULL + && (fOldLeftTop != fNewLeftTop + || fOldRightTop != fNewRightTop + || fOldLeftBottom != fNewLeftBottom + || fOldRightBottom != fNewRightBottom)) + return B_OK; + + return B_NO_INIT; +} + + +status_t +PerspectiveCommand::Perform() +{ + // objects are already transformed + return B_OK; +} + + +status_t +PerspectiveCommand::Undo() +{ + if (fTransformBox != NULL) { + fTransformBox->TransformTo(fOldLeftTop, fOldRightTop, fOldLeftBottom, fOldRightBottom); + return B_OK; + } + + fTransformer->TransformTo(fOldLeftTop, fOldRightTop, fOldLeftBottom, fOldRightBottom); + return B_OK; +} + + +status_t +PerspectiveCommand::Redo() +{ + if (fTransformBox != NULL) { + fTransformBox->TransformTo(fNewLeftTop, fNewRightTop, fNewLeftBottom, fNewRightBottom); + return B_OK; + } + + fTransformer->TransformTo(fNewLeftTop, fNewRightTop, fNewLeftBottom, fNewRightBottom); + return B_OK; +} + + +void +PerspectiveCommand::GetName(BString& name) +{ + name << B_TRANSLATE("Change perspective"); +} + + +// pragma mark - + + +void +PerspectiveCommand::PerspectiveBoxDeleted(const PerspectiveBox* box) +{ + if (fTransformBox == box) { + if (fTransformBox != NULL) + fTransformBox->RemoveListener(this); + fTransformBox = NULL; + } +} + + +// #pragma mark - + + +void +PerspectiveCommand::SetNewPerspective( + BPoint leftTop, BPoint rightTop, BPoint leftBottom, BPoint rightBottom) +{ + fNewLeftTop = leftTop; + fNewRightTop = rightTop; + fNewLeftBottom = leftBottom; + fNewRightBottom = rightBottom; +} diff --git a/src/apps/icon-o-matic/transformable/PerspectiveCommand.h b/src/apps/icon-o-matic/transformable/PerspectiveCommand.h new file mode 100644 index 0000000000..cfe8c83ae8 --- /dev/null +++ b/src/apps/icon-o-matic/transformable/PerspectiveCommand.h @@ -0,0 +1,63 @@ +/* + * Copyright 2006, 2023, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + * Zardshard + */ + +#ifndef PERSPECTIVE_COMMAND_H +#define PERSPECTIVE_COMMAND_H + + +#include + +#include "Command.h" +#include "PerspectiveBox.h" + + +class PerspectiveTransformer; + + +class PerspectiveCommand : public Command, public PerspectiveBoxListener { +public: + PerspectiveCommand(PerspectiveBox* box, + PerspectiveTransformer* transformer, + BPoint leftTop, BPoint rightTop, + BPoint leftBottom, BPoint rightBottom); + virtual ~PerspectiveCommand(); + + // Command interface + virtual status_t InitCheck(); + + virtual status_t Perform(); + virtual status_t Undo(); + virtual status_t Redo(); + + virtual void GetName(BString& name); + + // TransformBoxListener interface + virtual void PerspectiveBoxDeleted(const PerspectiveBox* box); + + // PerspectiveCommand + void SetNewPerspective( + BPoint leftTop, BPoint rightTop, + BPoint leftBottom, BPoint rightBottom); + +private: + PerspectiveBox* fTransformBox; + PerspectiveTransformer* fTransformer; + + BPoint fOldLeftTop; + BPoint fOldRightTop; + BPoint fOldLeftBottom; + BPoint fOldRightBottom; + + BPoint fNewLeftTop; + BPoint fNewRightTop; + BPoint fNewLeftBottom; + BPoint fNewRightBottom; +}; + +#endif // PERSPECTIVE_COMMAND_H diff --git a/src/apps/icon-o-matic/transformable/TransformBox.cpp b/src/apps/icon-o-matic/transformable/TransformBox.cpp index bd955e1b7f..7ad6909389 100644 --- a/src/apps/icon-o-matic/transformable/TransformBox.cpp +++ b/src/apps/icon-o-matic/transformable/TransformBox.cpp @@ -25,17 +25,7 @@ #define INSET 8.0 -TransformBoxListener::TransformBoxListener() -{ -} - - -TransformBoxListener::~TransformBoxListener() -{ -} - - -// #pragma mark - +using namespace TransformBoxStates; // constructor @@ -152,7 +142,6 @@ bool TransformBox::MouseDown(BPoint where) { fView->FilterMouse(&where); - // NOTE: filter mouse here and in MouseMoved only TransformToCanvas(where); fDragging = true; @@ -172,7 +161,6 @@ void TransformBox::MouseMoved(BPoint where) { fView->FilterMouse(&where); - // NOTE: filter mouse here and in MouseDown only TransformToCanvas(where); if (fMousePos != where) { @@ -236,12 +224,12 @@ TransformBox::Bounds() TransformFromCanvas(rb); TransformFromCanvas(c); - BRect r; - r.left = min5(lt.x, rt.x, lb.x, rb.x, c.x); - r.top = min5(lt.y, rt.y, lb.y, rb.y, c.y); - r.right = max5(lt.x, rt.x, lb.x, rb.x, c.x); - r.bottom = max5(lt.y, rt.y, lb.y, rb.y, c.y); - return r; + BRect bounds; + bounds.left = min5(lt.x, rt.x, lb.x, rb.x, c.x); + bounds.top = min5(lt.y, rt.y, lb.y, rb.y, c.y); + bounds.right = max5(lt.x, rt.x, lb.x, rb.x, c.x); + bounds.bottom = max5(lt.y, rt.y, lb.y, rb.y, c.y); + return bounds; } diff --git a/src/apps/icon-o-matic/transformable/TransformBox.h b/src/apps/icon-o-matic/transformable/TransformBox.h index 107dc227d5..923f11d1ad 100644 --- a/src/apps/icon-o-matic/transformable/TransformBox.h +++ b/src/apps/icon-o-matic/transformable/TransformBox.h @@ -5,7 +5,6 @@ * Authors: * Stephan Aßmus */ - #ifndef TRANSFORM_BOX_H #define TRANSFORM_BOX_H @@ -14,16 +13,21 @@ #include "ChannelTransform.h" #include "Manipulator.h" + +namespace TransformBoxStates { + class DragState; +} + class Command; class StateView; -class DragState; class TransformBox; class TransformCommand; + class TransformBoxListener { - public: - TransformBoxListener(); - virtual ~TransformBoxListener(); +public: + TransformBoxListener() {} + virtual ~TransformBoxListener() {} virtual void TransformBoxDeleted( const TransformBox* box) = 0; @@ -31,9 +35,8 @@ class TransformBoxListener { class TransformBox : public ChannelTransform, public Manipulator { - public: - TransformBox(StateView* view, - BRect box); +public: + TransformBox(StateView* view, BRect box); virtual ~TransformBox(); // Manipulator interface @@ -49,10 +52,10 @@ class TransformBox : public ChannelTransform, virtual BRect TrackingBounds(BView* withinView); virtual void ModifiersChanged(uint32 modifiers); - virtual bool HandleKeyDown(uint32 key, uint32 modifiers, - Command** _command); - virtual bool HandleKeyUp(uint32 key, uint32 modifiers, - Command** _command); + virtual bool HandleKeyDown(uint32 key, + uint32 modifiers, Command** _command); + virtual bool HandleKeyUp(uint32 key, + uint32 modifiers, Command** _command); virtual bool UpdateCursor(); @@ -90,15 +93,15 @@ class TransformBox : public ChannelTransform, bool AddListener(TransformBoxListener* listener); bool RemoveListener(TransformBoxListener* listener); - private: - DragState* _DragStateFor(BPoint canvasWhere, - float canvasZoom); +private: + TransformBoxStates::DragState* _DragStateFor( + BPoint canvasWhere, float canvasZoom); void _StrokeBWLine(BView* into, - BPoint from, BPoint to) const; + BPoint from, BPoint to) const; void _StrokeBWPoint(BView* into, - BPoint point, - double angle) const; + BPoint point, double angle) const; +private: BRect fOriginalBox; BPoint fLeftTop; @@ -110,7 +113,7 @@ class TransformBox : public ChannelTransform, BPoint fPivotOffset; TransformCommand* fCurrentCommand; - DragState* fCurrentState; + TransformBoxStates::DragState* fCurrentState; bool fDragging; BPoint fMousePos; @@ -120,25 +123,25 @@ class TransformBox : public ChannelTransform, BList fListeners; - protected: +protected: void _NotifyDeleted() const; // "static" state objects StateView* fView; - DragState* fDragLTState; - DragState* fDragRTState; - DragState* fDragLBState; - DragState* fDragRBState; + TransformBoxStates::DragState* fDragLTState; + TransformBoxStates::DragState* fDragRTState; + TransformBoxStates::DragState* fDragLBState; + TransformBoxStates::DragState* fDragRBState; - DragState* fDragLState; - DragState* fDragRState; - DragState* fDragTState; - DragState* fDragBState; + TransformBoxStates::DragState* fDragLState; + TransformBoxStates::DragState* fDragRState; + TransformBoxStates::DragState* fDragTState; + TransformBoxStates::DragState* fDragBState; - DragState* fRotateState; - DragState* fTranslateState; - DragState* fOffsetCenterState; + TransformBoxStates::DragState* fRotateState; + TransformBoxStates::DragState* fTranslateState; + TransformBoxStates::DragState* fOffsetCenterState; }; #endif // TRANSFORM_BOX_H diff --git a/src/apps/icon-o-matic/transformable/TransformBoxStates.cpp b/src/apps/icon-o-matic/transformable/TransformBoxStates.cpp index 8b6824a7d2..73e5c977fe 100644 --- a/src/apps/icon-o-matic/transformable/TransformBoxStates.cpp +++ b/src/apps/icon-o-matic/transformable/TransformBoxStates.cpp @@ -10,17 +10,14 @@ #include "TransformBoxStates.h" #include -#include #include #include -#include #include #include #include "cursors.h" #include "support.h" - #include "TransformBox.h" @@ -28,6 +25,9 @@ #define B_TRANSLATION_CONTEXT "Icon-O-Matic-TransformationBoxStates" +using namespace TransformBoxStates; + + DragState::DragState(TransformBox* parent) : fOrigin(0.0, 0.0), @@ -36,13 +36,6 @@ DragState::DragState(TransformBox* parent) } -void -DragState::SetOrigin(BPoint origin) -{ - fOrigin = origin; -} - - const char* DragState::ActionName() const { diff --git a/src/apps/icon-o-matic/transformable/TransformBoxStates.h b/src/apps/icon-o-matic/transformable/TransformBoxStates.h index ff4cdf1e73..820fd273aa 100644 --- a/src/apps/icon-o-matic/transformable/TransformBoxStates.h +++ b/src/apps/icon-o-matic/transformable/TransformBoxStates.h @@ -14,16 +14,21 @@ #include + class BView; class TransformBox; + +namespace TransformBoxStates { + // base class class DragState { public: DragState(TransformBox* parent); virtual ~DragState() {} - virtual void SetOrigin(BPoint origin); + virtual void SetOrigin(BPoint origin) + { fOrigin = origin; } virtual void DragTo(BPoint current, uint32 modifiers) = 0; virtual void UpdateViewCursor(BView* view, BPoint current) const = 0; @@ -142,4 +147,6 @@ class OffsetCenterState : public DragState { virtual const char* ActionName() const; }; +} // TransformBoxStates namespace + #endif // TRANSFORM_BOX_STATES_H diff --git a/src/build/libbe/icon/Jamfile b/src/build/libbe/icon/Jamfile index 2da832d067..155c7106b7 100644 --- a/src/build/libbe/icon/Jamfile +++ b/src/build/libbe/icon/Jamfile @@ -52,11 +52,12 @@ BuildPlatformMergeObjectPIC icon_kit.o : # transformer AffineTransformer.cpp + CompoundStyleTransformer.cpp ContourTransformer.cpp PathSource.cpp PerspectiveTransformer.cpp StrokeTransformer.cpp - Transformer.cpp + StyleTransformer.cpp TransformerFactory.cpp Icon.cpp diff --git a/src/build/libicon/Jamfile b/src/build/libicon/Jamfile index cb97574afc..ffd645fade 100644 --- a/src/build/libicon/Jamfile +++ b/src/build/libicon/Jamfile @@ -50,11 +50,12 @@ BuildPlatformStaticLibrary libicon_build.a : # transformer AffineTransformer.cpp + CompoundStyleTransformer.cpp ContourTransformer.cpp PathSource.cpp PerspectiveTransformer.cpp StrokeTransformer.cpp - Transformer.cpp + StyleTransformer.cpp TransformerFactory.cpp Icon.cpp diff --git a/src/libs/icon/IconRenderer.cpp b/src/libs/icon/IconRenderer.cpp index 5a9e4fedc2..72c280c7a1 100644 --- a/src/libs/icon/IconRenderer.cpp +++ b/src/libs/icon/IconRenderer.cpp @@ -20,108 +20,142 @@ #include #include #include +#include +#include "CompoundStyleTransformer.h" #include "GradientTransformable.h" #include "Icon.h" #include "Shape.h" #include "Style.h" +#include "StyleTransformer.h" #include "VectorPath.h" using std::nothrow; class IconRenderer::StyleHandler { struct StyleItem { - Style* style; - Transformation transformation; + const Style* style; + StyleTransformer* transformer; }; public: #ifdef ICON_O_MATIC - StyleHandler(::GammaTable& gammaTable, bool showReferences) - : fStyles(20), - fGammaTable(gammaTable), - fShowReferences(showReferences), - fTransparent(0, 0, 0, 0), - fColor(0, 0, 0, 0) - {} + StyleHandler(::GammaTable& gammaTable, + bool showReferences); #else - StyleHandler(::GammaTable& gammaTable) - : fStyles(20), - fGammaTable(gammaTable), - fTransparent(0, 0, 0, 0), - fColor(0, 0, 0, 0) - {} -#endif // ICON_O_MATIC - - ~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; - - if (styleItem->style->Gradient()) - return false; - -#ifdef ICON_O_MATIC - if (styleItem->style->Bitmap() && fShowReferences) - return false; -#endif // ICON_O_MATIC - - return true; - } - - 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 - void _GenerateGradient(agg::rgba8* span, int x, int y, unsigned len, - GradientFunction function, int32 start, int32 end, - const agg::rgba8* gradientColors, Transformation& gradientTransform); -#ifdef ICON_O_MATIC - void _GenerateImage(agg::rgba8* span, int x, int y, - unsigned len, Style* style, Transformation& transform); + StyleHandler(::GammaTable& gammaTable); #endif - BList fStyles; - ::GammaTable& fGammaTable; + ~StyleHandler(); + + bool AddStyle(const Style* style, + const Transformable& transformation, + const Container* transformers); + + bool is_solid(unsigned styleIndex) const; + const agg::rgba8& color(unsigned styleIndex); + void generate_span(agg::rgba8* span, int x, int y, + unsigned len, unsigned styleIndex); + private: + StyleTransformer* _MergeTransformers( + const Transformable* styleTransformation, + const Container* transformers, + const Transformable* shapeTransformation); + + template + void _GenerateGradient(agg::rgba8* span, + int x, int y, unsigned len, + GradientFunction function, + int32 start, int32 end, + const agg::rgba8* gradientColors, + StyleTransformer* transformer); #ifdef ICON_O_MATIC - bool fShowReferences; + void _GenerateImage(agg::rgba8* span, + int x, int y, unsigned len, + const Style* style, + StyleTransformer* transformer); #endif - agg::rgba8 fTransparent; - agg::rgba8 fColor; + + private: + BList fStyles; + ::GammaTable& fGammaTable; +#ifdef ICON_O_MATIC + bool fShowReferences; +#endif + agg::rgba8 fTransparent; + agg::rgba8 fColor; }; + +#ifdef ICON_O_MATIC +IconRenderer::StyleHandler::StyleHandler(::GammaTable& gammaTable, bool showReferences) + : fStyles(20), + fGammaTable(gammaTable), + fShowReferences(showReferences), + fTransparent(0, 0, 0, 0), + fColor(0, 0, 0, 0) +{} +#else +IconRenderer::StyleHandler::StyleHandler(::GammaTable& gammaTable) + : fStyles(20), + fGammaTable(gammaTable), + fTransparent(0, 0, 0, 0), + fColor(0, 0, 0, 0) +{} +#endif + + +IconRenderer::StyleHandler::~StyleHandler() +{ + int32 count = fStyles.CountItems(); + for (int32 i = 0; i < count; i++) { + StyleItem* item = (StyleItem*)fStyles.ItemAtFast(i); + delete item->transformer; + delete item; + } +} + + +bool +IconRenderer::StyleHandler::AddStyle(const Style* style, + const Transformable& transformation, const Container* transformers) +{ + if (!style) + return false; + + StyleItem* item = new (nothrow) StyleItem; + if (!item) + return false; + + item->style = style; + + item->transformer = _MergeTransformers(style->Gradient(), transformers, &transformation); + item->transformer->Invert(); + + return fStyles.AddItem((void*)item); +} + + +bool +IconRenderer::StyleHandler::is_solid(unsigned styleIndex) const +{ + StyleItem* styleItem = (StyleItem*)fStyles.ItemAt(styleIndex); + if (!styleItem) + return true; + + if (styleItem->style->Gradient()) + return false; + +#ifdef ICON_O_MATIC + if (styleItem->style->Bitmap() && fShowReferences) + return false; +#endif // ICON_O_MATIC + + return true; +} + + const agg::rgba8& IconRenderer::StyleHandler::color(unsigned styleIndex) { @@ -164,12 +198,12 @@ IconRenderer::StyleHandler::generate_span(agg::rgba8* span, int x, int y, #ifdef ICON_O_MATIC if (styleItem->style->Bitmap()) { - _GenerateImage(span, x, y, len, styleItem->style, styleItem->transformation); + _GenerateImage(span, x, y, len, styleItem->style, styleItem->transformer); return; } #endif // ICON_O_MATIC - Style* style = styleItem->style; + const Style* style = styleItem->style; Gradient* gradient = style->Gradient(); const agg::rgba8* colors = style->GammaCorrectedColors(fGammaTable); @@ -177,70 +211,132 @@ IconRenderer::StyleHandler::generate_span(agg::rgba8* span, int x, int y, case GRADIENT_LINEAR: { agg::gradient_x function; _GenerateGradient(span, x, y, len, function, -64, 64, colors, - styleItem->transformation); + styleItem->transformer); break; } case GRADIENT_CIRCULAR: { agg::gradient_radial function; _GenerateGradient(span, x, y, len, function, 0, 64, colors, - styleItem->transformation); + styleItem->transformer); break; } case GRADIENT_DIAMOND: { agg::gradient_diamond function; _GenerateGradient(span, x, y, len, function, 0, 64, colors, - styleItem->transformation); + styleItem->transformer); break; } case GRADIENT_CONIC: { agg::gradient_conic function; _GenerateGradient(span, x, y, len, function, 0, 64, colors, - styleItem->transformation); + styleItem->transformer); break; } case GRADIENT_XY: { agg::gradient_xy function; _GenerateGradient(span, x, y, len, function, 0, 64, colors, - styleItem->transformation); + styleItem->transformer); break; } case GRADIENT_SQRT_XY: { agg::gradient_sqrt_xy function; _GenerateGradient(span, x, y, len, function, 0, 64, colors, - styleItem->transformation); + styleItem->transformer); break; } } } +StyleTransformer* +IconRenderer::StyleHandler::_MergeTransformers(const Transformable* styleTransformation, + const Container* transformers, const Transformable* shapeTransformation) +{ + // Figure out how large to make the array + int32 count = 0; + if (styleTransformation != NULL) + count++; + for (int i = 0; i < transformers->CountItems(); i++) { + if (dynamic_cast(transformers->ItemAtFast(i))) + count++; + } + count++; + + // Populate the array + StyleTransformer** styleTransformers = new (nothrow) StyleTransformer*[count]; + if (styleTransformers == NULL) + return NULL; + + int i = 0; + if (styleTransformation != NULL) + styleTransformers[i++] = new (nothrow) Transformable(*styleTransformation); + for (int j = 0; j < transformers->CountItems(); j++) { + Transformer* transformer = transformers->ItemAtFast(j); + if (dynamic_cast(transformer) != NULL) { + styleTransformers[i++] + = dynamic_cast(transformer->Clone()); + } + } + styleTransformers[i++] = new (nothrow) Transformable(*shapeTransformation); + + CompoundStyleTransformer* styleTransformer + = new (nothrow) CompoundStyleTransformer(styleTransformers, count); + if (styleTransformer == NULL) { + delete[] styleTransformers; + return NULL; + } + + return styleTransformer; +} + + template void IconRenderer::StyleHandler::_GenerateGradient(agg::rgba8* span, int x, int y, unsigned len, GradientFunction function, int32 start, int32 end, - const agg::rgba8* gradientColors, Transformation& gradientTransform) + const agg::rgba8* gradientColors, StyleTransformer* transformer) { + // TODO: performance could potentially be improved by avoiding recreating + // these objects on every span typedef agg::pod_auto_array ColorArray; - typedef agg::span_interpolator_linear<> Interpolator; - typedef agg::span_gradient GradientGenerator; - - Interpolator interpolator(gradientTransform); - ColorArray array(gradientColors); - GradientGenerator gradientGenerator(interpolator, function, array, - start, end); - gradientGenerator.generate(span, x, y, len); + if (transformer->IsLinear()) { + typedef agg::span_interpolator_linear + Interpolator; + typedef agg::span_gradient GradientGenerator; + + Interpolator interpolator(*transformer); + + GradientGenerator gradientGenerator(interpolator, function, array, + start, end); + + gradientGenerator.generate(span, x, y, len); + } else { + typedef agg::span_interpolator_trans + Interpolator; + typedef agg::span_gradient GradientGenerator; + + Interpolator interpolator(*transformer); + + GradientGenerator gradientGenerator(interpolator, function, array, + start, end); + + gradientGenerator.generate(span, x, y, len); + } } #ifdef ICON_O_MATIC void IconRenderer::StyleHandler::_GenerateImage(agg::rgba8* span, int x, int y, - unsigned len, Style* style, Transformation& transform) + unsigned len, const Style* style, StyleTransformer* transformer) { // bitmap BBitmap* bbitmap = style->Bitmap(); @@ -252,13 +348,16 @@ IconRenderer::StyleHandler::_GenerateImage(agg::rgba8* span, int x, int y, PixelFormat pixf_img(bitmap); // image interpolator - typedef agg::span_interpolator_linear<> interpolator_type; - interpolator_type interpolator(transform); + // TODO: performance could be improved by using agg_interpolator_linear + // where possible, similar to what _GenerateGradient does. + typedef agg::span_interpolator_trans + interpolator_type; + interpolator_type interpolator(*transformer); // image accessor attached to pixel format of bitmap - typedef agg::image_accessor_wrap source_type; - source_type source(pixf_img); + typedef agg::image_accessor_clip source_type; + agg::rgba8 background(0, 0, 0, 0); + source_type source(pixf_img, background); // image filter (nearest neighbor) typedef agg::span_image_filter_rgba_nn< @@ -424,7 +523,7 @@ IconRenderer::Demultiply() // #pragma mark - -typedef agg::conv_transform ScaledPath; +typedef agg::conv_transform ScaledPath; typedef agg::conv_transform HintedPath; @@ -467,11 +566,8 @@ IconRenderer::_Render(const BRect& r) continue; } - Transformation transform(*shape); + Transformable transform(*shape); transform.multiply(fGlobalTransform); - // NOTE: this works only because "agg::trans_affine", - // "Transformable" and "Transformation" are all the - // same thing Style* style = shape->Style(); if (!style) @@ -483,9 +579,11 @@ IconRenderer::_Render(const BRect& r) Gradient* gradient = style->Gradient(); bool styleAdded = false; if (gradient && !gradient->InheritTransformation()) { - styleAdded = styleHandler.AddStyle(style, fGlobalTransform); + styleAdded = styleHandler.AddStyle( + style, fGlobalTransform, NULL); } else { - styleAdded = styleHandler.AddStyle(style, transform); + styleAdded = styleHandler.AddStyle( + style, transform, shape->Transformers()); } if (!styleAdded) { diff --git a/src/libs/icon/IconRenderer.h b/src/libs/icon/IconRenderer.h index b9422e4ace..8fc8eba27d 100644 --- a/src/libs/icon/IconRenderer.h +++ b/src/libs/icon/IconRenderer.h @@ -21,6 +21,7 @@ #include #include "IconBuild.h" +#include "Transformable.h" class BBitmap; @@ -47,8 +48,6 @@ typedef agg::span_allocator SpanAllocator; typedef agg::rasterizer_compound_aa CompoundRasterizer; -typedef agg::trans_affine Transformation; - class IconRenderer { public: IconRenderer(BBitmap* bitmap); @@ -110,7 +109,7 @@ class IconRenderer { CompoundRasterizer fRasterizer; - Transformation fGlobalTransform; + Transformable fGlobalTransform; }; diff --git a/src/libs/icon/Jamfile b/src/libs/icon/Jamfile index 03a35dfee8..b4df7d9037 100644 --- a/src/libs/icon/Jamfile +++ b/src/libs/icon/Jamfile @@ -59,11 +59,12 @@ for architectureObject in [ MultiArchSubDirSetup ] { # transformer AffineTransformer.cpp + CompoundStyleTransformer.cpp ContourTransformer.cpp PathSource.cpp PerspectiveTransformer.cpp StrokeTransformer.cpp - Transformer.cpp + StyleTransformer.cpp TransformerFactory.cpp Icon.cpp diff --git a/src/libs/icon/flat_icon/FlatIconImporter.cpp b/src/libs/icon/flat_icon/FlatIconImporter.cpp index 8c4ec948a6..c3aadef8a6 100644 --- a/src/libs/icon/flat_icon/FlatIconImporter.cpp +++ b/src/libs/icon/flat_icon/FlatIconImporter.cpp @@ -1,9 +1,10 @@ /* - * Copyright 2006, Haiku. All rights reserved. + * Copyright 2006, 2023, Haiku. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Stephan Aßmus + * Zardshard */ #include "FlatIconImporter.h" @@ -435,7 +436,7 @@ FlatIconImporter::_ParsePaths(LittleEndianBuffer& buffer, // _ReadTransformer static Transformer* -_ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source) +_ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source, Shape* shape) { uint8 transformerType; if (!buffer.Read(transformerType)) @@ -479,9 +480,19 @@ _ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source) } case TRANSFORMER_TYPE_PERSPECTIVE: { PerspectiveTransformer* perspective - = new (nothrow) PerspectiveTransformer(source); - // TODO: upgrade AGG to be able to support storage of - // trans_perspective + = new (nothrow) PerspectiveTransformer(source, shape); + if (!perspective) + return NULL; + double matrix[9]; + for (int32 i = 0; i < 9; i++) { + float value; + if (!read_float_24(buffer, value)) { + delete perspective; + return NULL; + } + matrix[i] = value; + } + perspective->load_from(matrix); return perspective; } case TRANSFORMER_TYPE_STROKE: { @@ -601,7 +612,7 @@ FlatIconImporter::_ReadPathSourceShape(LittleEndianBuffer& buffer, return NULL; for (uint32 i = 0; i < transformerCount; i++) { Transformer* transformer - = _ReadTransformer(buffer, shape->VertexSource()); + = _ReadTransformer(buffer, shape->VertexSource(), shape); if (transformer && !shape->Transformers()->AddItem(transformer)) { delete transformer; return NULL; @@ -651,7 +662,3 @@ FlatIconImporter::_ParseShapes(LittleEndianBuffer& buffer, return B_OK; } - - - - diff --git a/src/libs/icon/generic/VertexSource.h b/src/libs/icon/generic/VertexSource.h new file mode 100644 index 0000000000..3c1c9d0ded --- /dev/null +++ b/src/libs/icon/generic/VertexSource.h @@ -0,0 +1,36 @@ +/* + * Copyright 2006-2007, 2023, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + * Zardshard + */ +#ifndef VERTEX_SOURCE_H +#define VERTEX_SOURCE_H + + +#include "IconBuild.h" + + +_BEGIN_ICON_NAMESPACE + + +class VertexSource { + public: + VertexSource() {} + virtual ~VertexSource() {} + + virtual void rewind(unsigned path_id) = 0; + virtual unsigned vertex(double* x, double* y) = 0; + + /*! Determines whether open paths should be closed or left open. */ + virtual bool WantsOpenPaths() const = 0; + virtual double ApproximationScale() const = 0; +}; + + +_END_ICON_NAMESPACE + + +#endif // VERTEX_SOURCE_H diff --git a/src/libs/icon/shape/Shape.cpp b/src/libs/icon/shape/Shape.cpp index a4534902a7..b1044666f0 100644 --- a/src/libs/icon/shape/Shape.cpp +++ b/src/libs/icon/shape/Shape.cpp @@ -24,6 +24,7 @@ # include "PropertyObject.h" #endif // ICON_O_MATIC #include "Container.h" +#include "PathTransformer.h" #include "Style.h" #include "TransformerFactory.h" #include "VectorPath.h" @@ -130,7 +131,7 @@ Shape::Shape(const Shape& other) int32 count = other.Transformers()->CountItems(); for (int32 i = 0; i < count; i++) { Transformer* original = other.Transformers()->ItemAtFast(i); - Transformer* cloned = original->Clone(fPathSource); + Transformer* cloned = original->Clone(); if (!fTransformers.AddItem(cloned)) { delete cloned; break; @@ -181,7 +182,7 @@ Shape::Unarchive(BMessage* archive) i++) { Transformer* transformer = TransformerFactory::TransformerFor( - &transformerArchive, VertexSource()); + &transformerArchive, VertexSource(), this); if (!transformer || !fTransformers.AddItem(transformer)) { delete transformer; } @@ -452,9 +453,11 @@ Shape::VertexSource() int32 count = fTransformers.CountItems(); for (int32 i = 0; i < count; i++) { - Transformer* t = (Transformer*)fTransformers.ItemAtFast(i); - t->SetSource(*source); - source = t; + PathTransformer* t = dynamic_cast(fTransformers.ItemAtFast(i)); + if (t != NULL) { + t->SetSource(*source); + source = t; + } } if (fNeedsUpdate) { diff --git a/src/libs/icon/style/Style.h b/src/libs/icon/style/Style.h index 5607a1cec8..dbc4213ca9 100644 --- a/src/libs/icon/style/Style.h +++ b/src/libs/icon/style/Style.h @@ -86,7 +86,7 @@ class Style { // alpha only applies to bitmaps void SetAlpha(uint8 alpha) { fAlpha = alpha; Notify(); } - uint8 Alpha() + uint8 Alpha() const { return fAlpha; } #endif // ICON_O_MATIC diff --git a/src/libs/icon/transformable/Transformable.cpp b/src/libs/icon/transformable/Transformable.cpp index ac76b6ba15..a53ce43f64 100644 --- a/src/libs/icon/transformable/Transformable.cpp +++ b/src/libs/icon/transformable/Transformable.cpp @@ -1,9 +1,10 @@ /* - * Copyright 2006-2009, Haiku. + * Copyright 2006-2009, 2023, Haiku. * Distributed under the terms of the MIT License. * * Authors: * Stephan Aßmus + * Zardshard */ #include "Transformable.h" @@ -11,31 +12,78 @@ #include #include -// constructor + Transformable::Transformable() : agg::trans_affine() { } -// copy constructor + Transformable::Transformable(const Transformable& other) : agg::trans_affine(other) { } -// destructor + Transformable::~Transformable() { } -// StoreTo + +// #pragma mark - + + +void +Transformable::Invert() +{ + if (!IsIdentity()) { + invert(); + TransformationChanged(); + } +} + + +// #pragma mark - + + +void +Transformable::InverseTransform(double* x, double* y) const +{ + inverse_transform(x, y); +} + + +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; + } +} + + +BPoint +Transformable::InverseTransform(const BPoint& point) const +{ + BPoint p(point); + InverseTransform(&p); + return p; +} + + void Transformable::StoreTo(double matrix[matrix_size]) const { store_to(matrix); } -// LoadFrom + void Transformable::LoadFrom(const double matrix[matrix_size]) { @@ -50,7 +98,7 @@ Transformable::LoadFrom(const double matrix[matrix_size]) } } -// SetTransform + void Transformable::SetTransform(const Transformable& other) { @@ -60,7 +108,7 @@ Transformable::SetTransform(const Transformable& other) } } -// operator= + Transformable& Transformable::operator=(const Transformable& other) { @@ -72,7 +120,7 @@ Transformable::operator=(const Transformable& other) return *this; } -// Multiply + Transformable& Transformable::Multiply(const Transformable& other) { @@ -83,7 +131,7 @@ Transformable::Multiply(const Transformable& other) return *this; } -// Reset + void Transformable::Reset() { @@ -93,17 +141,7 @@ Transformable::Reset() } } -// Invert -void -Transformable::Invert() -{ - if (!IsIdentity()) { - invert(); - TransformationChanged(); - } -} -// IsIdentity bool Transformable::IsIdentity() const { @@ -119,7 +157,7 @@ Transformable::IsIdentity() const return false; } -// IsTranslationOnly + bool Transformable::IsTranslationOnly() const { @@ -133,7 +171,7 @@ Transformable::IsTranslationOnly() const return false; } -// IsNotDistorted + bool Transformable::IsNotDistorted() const { @@ -142,7 +180,7 @@ Transformable::IsNotDistorted() const return (m[0] == m[3]); } -// IsValid + bool Transformable::IsValid() const { @@ -151,7 +189,7 @@ Transformable::IsValid() const return ((m[0] * m[3] - m[1] * m[2]) != 0.0); } -// operator== + bool Transformable::operator==(const Transformable& other) const { @@ -162,74 +200,13 @@ Transformable::operator==(const Transformable& other) const 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) @@ -237,13 +214,14 @@ 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 { @@ -253,10 +231,10 @@ Transformable::TransformBounds(BRect bounds) const BPoint lb(bounds.left, bounds.bottom); BPoint rb(bounds.right, bounds.bottom); - Transform(<); - Transform(&rt); - Transform(&lb); - Transform(&rb); + StyleTransformer::Transform(<); + StyleTransformer::Transform(&rt); + StyleTransformer::Transform(&lb); + StyleTransformer::Transform(&rb); return BRect(floorf(min4(lt.x, rt.x, lb.x, rb.x)), floorf(min4(lt.y, rt.y, lb.y, rb.y)), @@ -266,7 +244,7 @@ Transformable::TransformBounds(BRect bounds) const return bounds; } -// TranslateBy + void Transformable::TranslateBy(BPoint offset) { @@ -276,7 +254,7 @@ Transformable::TranslateBy(BPoint offset) } } -// RotateBy + void Transformable::RotateBy(BPoint origin, double degrees) { @@ -288,7 +266,7 @@ Transformable::RotateBy(BPoint origin, double degrees) } } -// ScaleBy + void Transformable::ScaleBy(BPoint origin, double xScale, double yScale) { @@ -300,7 +278,7 @@ Transformable::ScaleBy(BPoint origin, double xScale, double yScale) } } -// ShearBy + void Transformable::ShearBy(BPoint origin, double xShear, double yShear) { @@ -312,7 +290,7 @@ Transformable::ShearBy(BPoint origin, double xShear, double yShear) } } -// TransformationChanged + void Transformable::TransformationChanged() { diff --git a/src/libs/icon/transformable/Transformable.h b/src/libs/icon/transformable/Transformable.h index 9d7518e0f1..043c62f1f4 100644 --- a/src/libs/icon/transformable/Transformable.h +++ b/src/libs/icon/transformable/Transformable.h @@ -1,9 +1,10 @@ /* - * Copyright 2006, Haiku. + * Copyright 2006, 2023, Haiku. * Distributed under the terms of the MIT License. * * Authors: * Stephan Aßmus + * Zardshard */ #ifndef TRANSFORMABLE_H @@ -14,12 +15,17 @@ #include #include "IconBuild.h" +#include "StyleTransformer.h" +#include "Transformer.h" _BEGIN_ICON_NAMESPACE -class Transformable : public agg::trans_affine { +/*! The standard affine transformation. */ +// TODO: combine with AffineTransformer +class Transformable : public StyleTransformer, + public agg::trans_affine { public: enum { matrix_size = 6, @@ -29,6 +35,18 @@ class Transformable : public agg::trans_affine { Transformable(const Transformable& other); virtual ~Transformable(); + // StyleTransformer interface + virtual void transform(double* x, double* y) const + { return agg::trans_affine::transform(x, y); } + virtual void Invert(); + virtual bool IsLinear() + { return true; } + + // Transformable + void InverseTransform(double* x, double* y) const; + void InverseTransform(BPoint* point) const; + BPoint InverseTransform(const BPoint& point) const; + void StoreTo(double matrix[matrix_size]) const; void LoadFrom(const double matrix[matrix_size]); @@ -38,8 +56,6 @@ class Transformable : public agg::trans_affine { Transformable& Multiply(const Transformable& other); virtual void Reset(); - void Invert(); - bool IsIdentity() const; bool IsTranslationOnly() const; bool IsNotDistorted() const; @@ -48,15 +64,6 @@ class Transformable : public agg::trans_affine { 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; @@ -70,7 +77,7 @@ class Transformable : public agg::trans_affine { virtual void TransformationChanged(); // hook function that is called when the transformation // is changed for some reason - + virtual void PrintToStream() const; }; @@ -82,4 +89,3 @@ _USING_ICON_NAMESPACE #endif // TRANSFORMABLE_H - diff --git a/src/libs/icon/transformer/AffineTransformer.cpp b/src/libs/icon/transformer/AffineTransformer.cpp index 2b87ce5492..2d7d3fb088 100644 --- a/src/libs/icon/transformer/AffineTransformer.cpp +++ b/src/libs/icon/transformer/AffineTransformer.cpp @@ -26,7 +26,8 @@ using std::nothrow; // constructor AffineTransformer::AffineTransformer(VertexSource& source) - : Transformer(source, "Transformation"), + : Transformer("Transformation"), + PathTransformer(source), Affine(source, *this) { } @@ -34,7 +35,8 @@ AffineTransformer::AffineTransformer(VertexSource& source) // constructor AffineTransformer::AffineTransformer(VertexSource& source, BMessage* archive) - : Transformer(source, archive), + : Transformer(archive), + PathTransformer(source), Affine(source, *this) { if (!archive) @@ -57,9 +59,9 @@ AffineTransformer::~AffineTransformer() // Clone Transformer* -AffineTransformer::Clone(VertexSource& source) const +AffineTransformer::Clone() const { - AffineTransformer* clone = new (nothrow) AffineTransformer(source); + AffineTransformer* clone = new (nothrow) AffineTransformer(fSource); if (clone) clone->multiply(*this); return clone; @@ -83,7 +85,7 @@ AffineTransformer::vertex(double* x, double* y) void AffineTransformer::SetSource(VertexSource& source) { - Transformer::SetSource(source); + PathTransformer::SetSource(source); Affine::attach(source); } diff --git a/src/libs/icon/transformer/AffineTransformer.h b/src/libs/icon/transformer/AffineTransformer.h index 929217e866..6eee7c43ab 100644 --- a/src/libs/icon/transformer/AffineTransformer.h +++ b/src/libs/icon/transformer/AffineTransformer.h @@ -10,6 +10,7 @@ #include "IconBuild.h" +#include "PathTransformer.h" #include "Transformer.h" #include @@ -23,6 +24,7 @@ typedef agg::conv_transform Affine; class AffineTransformer : public Transformer, + public PathTransformer, public Affine, public agg::trans_affine { public: @@ -38,8 +40,10 @@ class AffineTransformer : public Transformer, virtual ~AffineTransformer(); - virtual Transformer* Clone(VertexSource& source) const; + // Transformer interface + virtual Transformer* Clone() const; + // PathTransformer interface virtual void rewind(unsigned path_id); virtual unsigned vertex(double* x, double* y); diff --git a/src/libs/icon/transformer/CompoundStyleTransformer.cpp b/src/libs/icon/transformer/CompoundStyleTransformer.cpp new file mode 100644 index 0000000000..cc0390f081 --- /dev/null +++ b/src/libs/icon/transformer/CompoundStyleTransformer.cpp @@ -0,0 +1,72 @@ +/* + * Copyright 2023, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Zardshard + */ + + +#include "CompoundStyleTransformer.h" + +#include + + +_USING_ICON_NAMESPACE + + +CompoundStyleTransformer::CompoundStyleTransformer( + StyleTransformer** transformers, int32 count) + : + fTransformers(transformers), + fCount(count) +{ +} + + +CompoundStyleTransformer::~CompoundStyleTransformer() +{ + for (int i = 0; i < fCount; i++) + delete fTransformers[i]; + delete[] fTransformers; +} + + +void +CompoundStyleTransformer::transform(double* x, double* y) const +{ + for (int i = 0; i < fCount; i++) { + if (fTransformers[i] != NULL) + fTransformers[i]->transform(x, y); + } +} + + +void +CompoundStyleTransformer::Invert() +{ + // reverse order of pipeline + StyleTransformer* oldOrder[fCount]; + memcpy(oldOrder, fTransformers, fCount * sizeof(StyleTransformer*)); + for (int i = 0; i < fCount; i++) { + fTransformers[fCount-i-1] = oldOrder[i]; + } + + // invert individual transformations + for (int i = 0; i < fCount; i++) { + if (fTransformers[i] != NULL) + fTransformers[i]->Invert(); + } +} + + +bool +CompoundStyleTransformer::IsLinear() +{ + bool linear = true; + for (int i = 0; i < fCount; i++) { + if (fTransformers[i] != NULL) + linear &= fTransformers[i]->IsLinear(); + } + return linear; +} diff --git a/src/libs/icon/transformer/CompoundStyleTransformer.h b/src/libs/icon/transformer/CompoundStyleTransformer.h new file mode 100644 index 0000000000..b4b622f829 --- /dev/null +++ b/src/libs/icon/transformer/CompoundStyleTransformer.h @@ -0,0 +1,51 @@ +/* + * Copyright 2023, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Zardshard + */ +#ifndef COMPOUND_STYLE_TRANSFORMER_H +#define COMPOUND_STYLE_TRANSFORMER_H + + +#include + +#include "IconBuild.h" +#include "StyleTransformer.h" + + +_BEGIN_ICON_NAMESPACE + +class VertexSource; +class StyleTransformer; + + +/*! Allows turning an array of StyleTransformers into a single StyleTransformer. + + \note This class is not meant to be exposed to the GUI or saved in a file. It + is currently only used for rendering. +*/ +class CompoundStyleTransformer : public StyleTransformer { +public: + CompoundStyleTransformer( + StyleTransformer** transformers, + int32 count); + virtual ~CompoundStyleTransformer(); + + // StyleTransformer interface + virtual void transform(double* x, double* y) const; + virtual void Invert(); + + virtual bool IsLinear(); + +private: + StyleTransformer** fTransformers; + int32 fCount; +}; + + +_END_ICON_NAMESPACE + + +#endif // COMPOUND_STYLE_TRANSFORMER_H diff --git a/src/libs/icon/transformer/ContourTransformer.cpp b/src/libs/icon/transformer/ContourTransformer.cpp index a120e8291f..a569513f45 100644 --- a/src/libs/icon/transformer/ContourTransformer.cpp +++ b/src/libs/icon/transformer/ContourTransformer.cpp @@ -27,7 +27,8 @@ using std::nothrow; // constructor ContourTransformer::ContourTransformer(VertexSource& source) - : Transformer(source, "Contour"), + : Transformer("Contour"), + PathTransformer(source), Contour(source) { auto_detect_orientation(true); @@ -36,7 +37,8 @@ ContourTransformer::ContourTransformer(VertexSource& source) // constructor ContourTransformer::ContourTransformer(VertexSource& source, BMessage* archive) - : Transformer(source, archive), + : Transformer(archive), + PathTransformer(source), Contour(source) { auto_detect_orientation(true); @@ -69,9 +71,9 @@ ContourTransformer::~ContourTransformer() // Clone Transformer* -ContourTransformer::Clone(VertexSource& source) const +ContourTransformer::Clone() const { - ContourTransformer* clone = new (nothrow) ContourTransformer(source); + ContourTransformer* clone = new (nothrow) ContourTransformer(fSource); if (clone) { clone->line_join(line_join()); clone->inner_join(inner_join()); @@ -101,7 +103,7 @@ ContourTransformer::vertex(double* x, double* y) void ContourTransformer::SetSource(VertexSource& source) { - Transformer::SetSource(source); + PathTransformer::SetSource(source); Contour::attach(source); } diff --git a/src/libs/icon/transformer/ContourTransformer.h b/src/libs/icon/transformer/ContourTransformer.h index 258528988e..11983be469 100644 --- a/src/libs/icon/transformer/ContourTransformer.h +++ b/src/libs/icon/transformer/ContourTransformer.h @@ -10,6 +10,7 @@ #include "IconBuild.h" +#include "PathTransformer.h" #include "Transformer.h" #include @@ -21,6 +22,7 @@ _BEGIN_ICON_NAMESPACE typedef agg::conv_contour Contour; class ContourTransformer : public Transformer, + public PathTransformer, public Contour { public: enum { @@ -35,10 +37,12 @@ class ContourTransformer : public Transformer, virtual ~ContourTransformer(); - virtual Transformer* Clone(VertexSource& source) const; + // Transformer interface + virtual Transformer* Clone() const; + // PathTransformer interface virtual void rewind(unsigned path_id); - virtual unsigned vertex(double* x, double* y); + virtual unsigned vertex(double* x, double* y); virtual void SetSource(VertexSource& source); diff --git a/src/libs/icon/transformer/PathTransformer.h b/src/libs/icon/transformer/PathTransformer.h new file mode 100644 index 0000000000..eb75be76e9 --- /dev/null +++ b/src/libs/icon/transformer/PathTransformer.h @@ -0,0 +1,51 @@ +/* + * Copyright 2006-2007, 2023, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + * Zardshard + */ +#ifndef PATH_TRANSFORMER_H +#define PATH_TRANSFORMER_H + + +#include "IconBuild.h" +#include "VertexSource.h" + + +_BEGIN_ICON_NAMESPACE + + +/*! A transformation to a VertexSource. + It can add points, move them around, turn them to curves, etc. +*/ +class PathTransformer : public VertexSource +{ +public: + PathTransformer(VertexSource& source) + : fSource(source) {} + virtual ~PathTransformer() {} + + // PathTransformer + virtual void rewind(unsigned path_id) + { fSource.rewind(path_id); } + virtual unsigned vertex(double* x, double* y) + { return fSource.vertex(x, y); } + + virtual void SetSource(VertexSource& source) + { fSource = source; } + + virtual bool WantsOpenPaths() const + { return fSource.WantsOpenPaths(); } + virtual double ApproximationScale() const + { return fSource.ApproximationScale(); } + +protected: + VertexSource& fSource; +}; + + +_END_ICON_NAMESPACE + +#endif // PATH_TRANSFORMER_H diff --git a/src/libs/icon/transformer/PerspectiveTransformer.cpp b/src/libs/icon/transformer/PerspectiveTransformer.cpp index 33600645af..f4659c846f 100644 --- a/src/libs/icon/transformer/PerspectiveTransformer.cpp +++ b/src/libs/icon/transformer/PerspectiveTransformer.cpp @@ -1,108 +1,341 @@ /* - * Copyright 2006-2007, Haiku. + * Copyright 2006-2007, 2023, Haiku. * Distributed under the terms of the MIT License. * * Authors: * Stephan Aßmus + * Zardshard */ #include "PerspectiveTransformer.h" -#ifdef ICON_O_MATIC -# include -#endif - #include +#include + +#include +#include +#include + +#include "Shape.h" _USING_ICON_NAMESPACE using std::nothrow; -// constructor -PerspectiveTransformer::PerspectiveTransformer(VertexSource& source) - : Transformer(source, "Perspective"), - Perspective(source, *this) +PerspectiveTransformer::PerspectiveTransformer(VertexSource& source, Shape* shape) + : Transformer("Perspective"), + PathTransformer(source), + Perspective(source, *this), + fShape(shape) +#ifdef ICON_O_MATIC + , fInverted(false) +#endif { +#ifdef ICON_O_MATIC + if (fShape != NULL) { + fShape->AcquireReference(); + fShape->AddObserver(this); + ObjectChanged(fShape); // finish initialization + } +#endif } -// constructor -PerspectiveTransformer::PerspectiveTransformer(VertexSource& source, - BMessage* archive) - : Transformer(source, archive), - Perspective(source, *this) + +PerspectiveTransformer::PerspectiveTransformer( + VertexSource& source, Shape* shape, BMessage* archive) + : Transformer(archive), + PathTransformer(source), + Perspective(source, *this), + fShape(shape) +#ifdef ICON_O_MATIC + , fInverted(false) +#endif { - // TODO: upgrade AGG to be able to use load_from() etc + double matrix[9]; + for (int i = 0; i < 9; i++) { + if (archive->FindDouble("matrix", i, &matrix[i]) != B_OK) + matrix[i] = 0; + } + load_from(matrix); + +#ifdef ICON_O_MATIC + if (fShape != NULL) { + fShape->AcquireReference(); + fShape->AddObserver(this); + ObjectChanged(fShape); // finish initialization + } +#endif } -// destructor + +PerspectiveTransformer::PerspectiveTransformer(const PerspectiveTransformer& other) +#ifdef ICON_O_MATIC + : Transformer(other.Name()), +#else + : Transformer(""), +#endif + PathTransformer(other.fSource), + Perspective(fSource, *this), + fShape(other.fShape) +#ifdef ICON_O_MATIC + , fInverted(other.fInverted), + fFromBox(other.fFromBox), + fToLeftTop(other.fToLeftTop), + fToRightTop(other.fToRightTop), + fToLeftBottom(other.fToLeftBottom), + fToRightBottom(other.fToRightBottom), + fValid(other.fValid) +#endif +{ + double matrix[9]; + other.store_to(matrix); + load_from(matrix); + +#ifdef ICON_O_MATIC + if (fShape != NULL) { + fShape->AcquireReference(); + fShape->AddObserver(this); + } +#endif +} + + PerspectiveTransformer::~PerspectiveTransformer() { -} - -// Clone -Transformer* -PerspectiveTransformer::Clone(VertexSource& source) const -{ - PerspectiveTransformer* clone - = new (nothrow) PerspectiveTransformer(source); - if (clone) { -// TODO: upgrade AGG -// clone->multiply(*this); +#ifdef ICON_O_MATIC + if (fShape != NULL) { + fShape->RemoveObserver(this); + fShape->ReleaseReference(); } - return clone; +#endif } -// rewind + +// #pragma mark - + + +Transformer* +PerspectiveTransformer::Clone() const +{ + return new (nothrow) PerspectiveTransformer(*this); +} + + +// #pragma mark - + + void PerspectiveTransformer::rewind(unsigned path_id) { Perspective::rewind(path_id); } -// vertex + unsigned PerspectiveTransformer::vertex(double* x, double* y) { +#ifdef ICON_O_MATIC + if (fValid) + return Perspective::vertex(x, y); + else + return agg::path_cmd_stop; +#else return Perspective::vertex(x, y); +#endif } -// SetSource + void PerspectiveTransformer::SetSource(VertexSource& source) { - Transformer::SetSource(source); + PathTransformer::SetSource(source); Perspective::attach(source); + +#ifdef ICON_O_MATIC + ObjectChanged(fShape); +#endif } -// ApproximationScale + double PerspectiveTransformer::ApproximationScale() const { - // TODO: upgrade AGG - return fSource.ApproximationScale();// * scale(); + return fSource.ApproximationScale() * scale(); } + // #pragma mark - + +void +PerspectiveTransformer::Invert() +{ +#ifdef ICON_O_MATIC + fInverted = !fInverted; + + // TODO: degenerate matrices may not be adequately handled + bool degenerate = !invert(); + fValid = fValid && !degenerate; +#else + invert(); +#endif +} + + +// #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; + into->what = archive_code; - // TODO: upgrade AGG to be able to use store_to() + double matrix[9]; + store_to(matrix); + + for (int i = 0; i < 9; i++) { + if (ret == B_OK) + ret = into->AddDouble("matrix", matrix[i]); + } return ret; } + +// #prama mark - + + +void +PerspectiveTransformer::ObjectChanged(const Observable* object) +{ + if (fInverted) { + printf("calculating the validity or bounding box of an inverted " + "perspective transformer is currently unsupported."); + return; + } + + uint32 pathID[1]; + pathID[0] = 0; + double left, top, right, bottom; + agg::bounding_rect(fSource, pathID, 0, 1, &left, &top, &right, &bottom); + BRect newFromBox = BRect(left, top, right, bottom); + + // Stop if nothing we care about has changed + // TODO: Can this be done earlier? It would be nice to avoid having to + // recalculate the bounding box before realizing nothing needs to be done. + if (fFromBox == newFromBox) + return; + + fFromBox = newFromBox; + + _CheckValidity(); + + double x = fFromBox.left; double y = fFromBox.top; + Transform(&x, &y); + fToLeftTop = BPoint(x, y); + + x = fFromBox.right; y = fFromBox.top; + Transform(&x, &y); + fToRightTop = BPoint(x, y); + + x = fFromBox.left; y = fFromBox.bottom; + Transform(&x, &y); + fToLeftBottom = BPoint(x, y); + + x = fFromBox.right; y = fFromBox.bottom; + Transform(&x, &y); + fToRightBottom = BPoint(x, y); +} + + +// #pragma mark - + + +void +PerspectiveTransformer::TransformTo( + BPoint leftTop, BPoint rightTop, BPoint leftBottom, BPoint rightBottom) +{ + fToLeftTop = leftTop; + fToRightTop = rightTop; + fToLeftBottom = leftBottom; + fToRightBottom = rightBottom; + + double quad[8] = { + fToLeftTop.x, fToLeftTop.y, + fToRightTop.x, fToRightTop.y, + fToRightBottom.x, fToRightBottom.y, + fToLeftBottom.x, fToLeftBottom.y + }; + + if (!fInverted) { + rect_to_quad( + fFromBox.left, fFromBox.top, + fFromBox.right, fFromBox.bottom, quad); + } else { + quad_to_rect(quad, + fFromBox.left, fFromBox.top, + fFromBox.right, fFromBox.bottom); + } + + _CheckValidity(); + Notify(); +} + + +// #pragma mark - + + +void +PerspectiveTransformer::_CheckValidity() +{ + // Checks that none of the points are too close to the camera. These tend to + // lead to very big numbers or a divide by zero error. Also checks that all + // points are on the same side of the camera. Transformations with points on + // different sides of the camera look weird and tend to cause crashes. + + fValid = true; + double w; + bool positive; + + if (!fInverted) { + w = fFromBox.left * w0 + fFromBox.top * w1 + w2; + fValid &= (fabs(w) > 0.00001); + positive = w > 0; + + w = fFromBox.right * w0 + fFromBox.top * w1 + w2; + fValid &= (fabs(w) > 0.00001); + fValid &= (w>0)==positive; + + w = fFromBox.left * w0 + fFromBox.bottom * w1 + w2; + fValid &= (fabs(w) > 0.00001); + fValid &= (w>0)==positive; + + w = fFromBox.right * w0 + fFromBox.bottom * w1 + w2; + fValid &= (fabs(w) > 0.00001); + fValid &= (w>0)==positive; + } else { + w = fToLeftTop.x * w0 + fToLeftTop.y * w1 + w2; + fValid &= (fabs(w) > 0.00001); + positive = w > 0; + + w = fToRightTop.x * w0 + fToRightTop.y * w1 + w2; + fValid &= (fabs(w) > 0.00001); + fValid &= (w>0)==positive; + + w = fToLeftBottom.x * w0 + fToLeftBottom.y * w1 + w2; + fValid &= (fabs(w) > 0.00001); + fValid &= (w>0)==positive; + + w = fToRightBottom.x * w0 + fToRightBottom.y * w1 + w2; + fValid &= (fabs(w) > 0.00001); + fValid &= (w>0)==positive; + } +} + #endif // ICON_O_MATIC - - - diff --git a/src/libs/icon/transformer/PerspectiveTransformer.h b/src/libs/icon/transformer/PerspectiveTransformer.h index 6d2e246bd4..6b81e3ec6d 100644 --- a/src/libs/icon/transformer/PerspectiveTransformer.h +++ b/src/libs/icon/transformer/PerspectiveTransformer.h @@ -1,46 +1,76 @@ /* - * Copyright 2006-2007, Haiku. + * Copyright 2006-2007, 2023, Haiku. * Distributed under the terms of the MIT License. * * Authors: * Stephan Aßmus + * Zardshard */ #ifndef PERSPECTIVE_TRANSFORMER_H #define PERSPECTIVE_TRANSFORMER_H -#include "IconBuild.h" -#include "Transformer.h" +#include +#include #include #include +#include "IconBuild.h" +#include "Transformer.h" +#ifdef ICON_O_MATIC +#include "Observer.h" +#endif +#include "PathTransformer.h" +#include "StyleTransformer.h" +#include "VertexSource.h" + _BEGIN_ICON_NAMESPACE +class Shape; -typedef agg::conv_transform Perspective; +typedef agg::conv_transform Perspective; + +/*! Transforms from the VertexSource's bounding rect to the specified + quadrilateral. This class watches out for invalid transformations if + \c ICON_O_MATIC is set. +*/ class PerspectiveTransformer : public Transformer, + public PathTransformer, + public StyleTransformer, +#ifdef ICON_O_MATIC + public Observer, +#endif public Perspective, public agg::trans_perspective { - public: +public: enum { archive_code = 'prsp', }; - PerspectiveTransformer( - VertexSource& source); + /*! Initializes starting with the identity transformation. + A valid perspective transformation can be rendered invalid if the shape + changes. Listens to \a shape for updates and determines if the + transformation is still valid if \c ICON_O_MATIC is set. + */ PerspectiveTransformer( VertexSource& source, + Shape* shape); + PerspectiveTransformer( + VertexSource& source, + Shape* shape, BMessage* archive); + PerspectiveTransformer( + const PerspectiveTransformer& other); virtual ~PerspectiveTransformer(); // Transformer interface - virtual Transformer* Clone(VertexSource& source) const; + virtual Transformer* Clone() const; + // PathTransformer interface virtual void rewind(unsigned path_id); virtual unsigned vertex(double* x, double* y); @@ -48,11 +78,55 @@ class PerspectiveTransformer : public Transformer, virtual double ApproximationScale() const; + // StyleTransformer interface + virtual void transform(double* x, double* y) const +#ifdef ICON_O_MATIC + { if (fValid) agg::trans_perspective::transform(x, y); } +#else + { agg::trans_perspective::transform(x, y); } +#endif + + /*! Inverts the perspective transformation. + \warning This class can mostly only transform points when inverted. Most + other features either have not been tested or are missing. + */ + virtual void Invert(); + #ifdef ICON_O_MATIC // IconObject interface virtual status_t Archive(BMessage* into, bool deep = true) const; + // Observer interface + virtual void ObjectChanged(const Observable* object); + + // PerspectiveTransformer + void TransformTo(BPoint leftTop, BPoint rightTop, + BPoint leftBottom, BPoint rightBottom); + + BPoint LeftTop() + { return fToLeftTop; } + BPoint RightTop() + { return fToRightTop; } + BPoint LeftBottom() + { return fToLeftBottom; } + BPoint RightBottom() + { return fToRightBottom; } + +private: + void _CheckValidity(); +#endif // ICON_O_MATIC + +private: + Shape* fShape; +#ifdef ICON_O_MATIC + bool fInverted; + BRect fFromBox; + BPoint fToLeftTop; + BPoint fToRightTop; + BPoint fToLeftBottom; + BPoint fToRightBottom; + bool fValid; #endif }; diff --git a/src/libs/icon/transformer/StrokeTransformer.cpp b/src/libs/icon/transformer/StrokeTransformer.cpp index 25d64a4504..4ef926ea24 100644 --- a/src/libs/icon/transformer/StrokeTransformer.cpp +++ b/src/libs/icon/transformer/StrokeTransformer.cpp @@ -27,7 +27,8 @@ using std::nothrow; // constructor StrokeTransformer::StrokeTransformer(VertexSource& source) - : Transformer(source, "Stroke"), + : Transformer("Stroke"), + PathTransformer(source), Stroke(source) { } @@ -35,7 +36,8 @@ StrokeTransformer::StrokeTransformer(VertexSource& source) // constructor StrokeTransformer::StrokeTransformer(VertexSource& source, BMessage* archive) - : Transformer(source, archive), + : Transformer(archive), + PathTransformer(source), Stroke(source) { if (!archive) @@ -72,9 +74,9 @@ StrokeTransformer::~StrokeTransformer() // Clone Transformer* -StrokeTransformer::Clone(VertexSource& source) const +StrokeTransformer::Clone() const { - StrokeTransformer* clone = new (nothrow) StrokeTransformer(source); + StrokeTransformer* clone = new (nothrow) StrokeTransformer(fSource); if (clone) { clone->line_cap(line_cap()); clone->line_join(line_join()); @@ -105,7 +107,7 @@ StrokeTransformer::vertex(double* x, double* y) void StrokeTransformer::SetSource(VertexSource& source) { - Transformer::SetSource(source); + PathTransformer::SetSource(source); Stroke::attach(source); } diff --git a/src/libs/icon/transformer/StrokeTransformer.h b/src/libs/icon/transformer/StrokeTransformer.h index 011d0cc305..592530e2f4 100644 --- a/src/libs/icon/transformer/StrokeTransformer.h +++ b/src/libs/icon/transformer/StrokeTransformer.h @@ -10,6 +10,7 @@ #include "IconBuild.h" +#include "PathTransformer.h" #include "Transformer.h" #include @@ -21,6 +22,7 @@ _BEGIN_ICON_NAMESPACE typedef agg::conv_stroke Stroke; class StrokeTransformer : public Transformer, + public PathTransformer, public Stroke { public: enum { @@ -36,8 +38,9 @@ class StrokeTransformer : public Transformer, virtual ~StrokeTransformer(); // Transformer interface - virtual Transformer* Clone(VertexSource& source) const; + virtual Transformer* Clone() const; + // PathTransformer interface virtual void rewind(unsigned path_id); virtual unsigned vertex(double* x, double* y); diff --git a/src/libs/icon/transformer/StyleTransformer.cpp b/src/libs/icon/transformer/StyleTransformer.cpp new file mode 100644 index 0000000000..34b39e00d7 --- /dev/null +++ b/src/libs/icon/transformer/StyleTransformer.cpp @@ -0,0 +1,44 @@ +/* + * Copyright 2023, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + * Zardshard + */ + +#include "StyleTransformer.h" + +#include + + +_USING_ICON_NAMESPACE + + +StyleTransformer::~StyleTransformer() +{ +} + + +void +StyleTransformer::Transform(BPoint* point) const +{ + if (point) { + double x = point->x; + double y = point->y; + + Transform(&x, &y); + + point->x = x; + point->y = y; + } +} + + +BPoint +StyleTransformer::Transform(const BPoint& point) const +{ + BPoint p(point); + Transform(&p); + return p; +} diff --git a/src/libs/icon/transformer/StyleTransformer.h b/src/libs/icon/transformer/StyleTransformer.h new file mode 100644 index 0000000000..9fd6ae7b98 --- /dev/null +++ b/src/libs/icon/transformer/StyleTransformer.h @@ -0,0 +1,61 @@ +/* + * Copyright 2023, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + * Zardshard + */ +#ifndef STYLE_TRANSFORMER_H +#define STYLE_TRANSFORMER_H + + +#include "IconBuild.h" + + +class BPoint; + +_BEGIN_ICON_NAMESPACE + + +/*! Warps a shape's style. + Implements the same interface as any other class of the agg:trans_ series. + This class can be used wherever AGG needs a transformer (for example, + agg::span_interpolator_linear is valid). +*/ +class StyleTransformer { +public: + StyleTransformer() {} + virtual ~StyleTransformer(); + + /*! Transform a single point of the shape's style. + This function should be fast since it will be called many times. + + \note This function is lowercase so that it satisfies the role of an agg + transformer + */ + virtual void transform(double* x, double* y) const = 0; + + /*! Alias of \c transform. + Use of this in our code is preffered because it follows the normal + capitalization scheme. + */ + void Transform(double* x, double* y) const + { transform(x, y); } + void Transform(BPoint* point) const; + BPoint Transform(const BPoint& point) const; + + virtual void Invert() = 0; + + /*! Is the transformation a linear transformation? + This allows using linear interpolation instead of calling \c transform + for each point. */ + virtual bool IsLinear() + { return false; } +}; + + +_END_ICON_NAMESPACE + + +#endif // STYLE_TRANSFORMER_H diff --git a/src/libs/icon/transformer/Transformer.cpp b/src/libs/icon/transformer/Transformer.cpp deleted file mode 100644 index d9098c8c0e..0000000000 --- a/src/libs/icon/transformer/Transformer.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2006-2007, Haiku. - * Distributed under the terms of the MIT License. - * - * Authors: - * Stephan Aßmus - */ - - -#include "Transformer.h" - - -_USING_ICON_NAMESPACE - - -// 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) -{ -} - -// constructor -Transformer::Transformer(VertexSource& source, - BMessage* archive) -#ifdef ICON_O_MATIC - : IconObject(archive), -#else - : -#endif - fSource(source) -{ -} - -// 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(); -} - diff --git a/src/libs/icon/transformer/Transformer.h b/src/libs/icon/transformer/Transformer.h index 663fe00b54..4b1bd9be18 100644 --- a/src/libs/icon/transformer/Transformer.h +++ b/src/libs/icon/transformer/Transformer.h @@ -17,52 +17,35 @@ #endif #include "IconBuild.h" +#include "VertexSource.h" _BEGIN_ICON_NAMESPACE -class VertexSource { - public: - VertexSource(); - virtual ~VertexSource(); - - virtual void rewind(unsigned path_id) = 0; - virtual unsigned vertex(double* x, double* y) = 0; - - /*! Determines whether open paths should be closed or left open. */ - virtual bool WantsOpenPaths() const = 0; - virtual double ApproximationScale() const = 0; -}; - - +/*! Base class for all transformers. + All child classes should inherit either PathTransformer, StyleTransformer, + or both. +*/ #ifdef ICON_O_MATIC -class Transformer : public VertexSource, - public IconObject { +class Transformer : public IconObject { #else -class Transformer : public VertexSource { + class Transformer { +#endif +public: +#ifdef ICON_O_MATIC + Transformer(const char* name) + : IconObject(name) {} + Transformer(BMessage* archive) + : IconObject(archive) {} +#else + Transformer(const char* name) {} + Transformer(BMessage* archive) {} #endif - public: - Transformer(VertexSource& source, - const char* name); - Transformer(VertexSource& source, - BMessage* archive); - virtual ~Transformer(); + 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; + virtual Transformer* Clone() const = 0; }; diff --git a/src/libs/icon/transformer/TransformerFactory.cpp b/src/libs/icon/transformer/TransformerFactory.cpp index 0e9c6d1c9b..acb3ab7f94 100644 --- a/src/libs/icon/transformer/TransformerFactory.cpp +++ b/src/libs/icon/transformer/TransformerFactory.cpp @@ -11,6 +11,7 @@ #include "AffineTransformer.h" #include "ContourTransformer.h" #include "PerspectiveTransformer.h" +#include "Shape.h" #include "StrokeTransformer.h" #ifdef ICON_O_MATIC @@ -24,13 +25,13 @@ _USING_ICON_NAMESPACE // TransformerFor Transformer* -TransformerFactory::TransformerFor(uint32 type, VertexSource& source) +TransformerFactory::TransformerFor(uint32 type, VertexSource& source, Shape* shape) { switch (type) { case AFFINE_TRANSFORMER: return new AffineTransformer(source); case PERSPECTIVE_TRANSFORMER: - return new PerspectiveTransformer(source); + return new PerspectiveTransformer(source, shape); case CONTOUR_TRANSFORMER: return new ContourTransformer(source); case STROKE_TRANSFORMER: @@ -42,14 +43,13 @@ TransformerFactory::TransformerFor(uint32 type, VertexSource& source) // TransformerFor Transformer* -TransformerFactory::TransformerFor(BMessage* message, - VertexSource& source) +TransformerFactory::TransformerFor(BMessage* message, VertexSource& source, Shape* shape) { switch (message->what) { case AffineTransformer::archive_code: return new AffineTransformer(source, message); case PerspectiveTransformer::archive_code: - return new PerspectiveTransformer(source, message); + return new PerspectiveTransformer(source, shape, message); case ContourTransformer::archive_code: return new ContourTransformer(source, message); case StrokeTransformer::archive_code: diff --git a/src/libs/icon/transformer/TransformerFactory.h b/src/libs/icon/transformer/TransformerFactory.h index 584a661f35..9baf26717e 100644 --- a/src/libs/icon/transformer/TransformerFactory.h +++ b/src/libs/icon/transformer/TransformerFactory.h @@ -20,6 +20,7 @@ class BMessage; _BEGIN_ICON_NAMESPACE +class Shape; class Transformer; class VertexSource; @@ -35,10 +36,12 @@ class TransformerFactory { public: static Transformer* TransformerFor(uint32 type, - VertexSource& source); + VertexSource& source, + Shape* shape); static Transformer* TransformerFor(BMessage* archive, - VertexSource& source); + VertexSource& source, + Shape* shape); };