diff --git a/src/apps/icon-o-matic/Jamfile b/src/apps/icon-o-matic/Jamfile index cd4c32ac33..4e29ea1a1a 100644 --- a/src/apps/icon-o-matic/Jamfile +++ b/src/apps/icon-o-matic/Jamfile @@ -87,8 +87,10 @@ Application Icon-O-Matic : AddPointCommand.cpp ChangePointCommand.cpp InsertPointCommand.cpp + MoveShapesCommand.cpp PathCommand.cpp RemovePointsCommand.cpp + RemoveShapesCommand.cpp # style Style.cpp StyleManager.cpp diff --git a/src/apps/icon-o-matic/MainWindow.cpp b/src/apps/icon-o-matic/MainWindow.cpp index 2bf12602a2..1cb141b86e 100644 --- a/src/apps/icon-o-matic/MainWindow.cpp +++ b/src/apps/icon-o-matic/MainWindow.cpp @@ -93,11 +93,11 @@ MainWindow::_Init() fPathListView->SetPathContainer(fDocument->Icon()->Paths()); // fPathListView->SetCommandStack(fDocument->CommandStack()); -// fPathListView->SetSelection(fDocument->Selection()); + fPathListView->SetSelection(fDocument->Selection()); fShapeListView->SetShapeContainer(fDocument->Icon()->Shapes()); -// fShapeListView->SetCommandStack(fDocument->CommandStack()); -// fShapeListView->SetSelection(fDocument->Selection()); + fShapeListView->SetCommandStack(fDocument->CommandStack()); + fShapeListView->SetSelection(fDocument->Selection()); fIconPreview16->SetIcon(fDocument->Icon()); fIconPreview32->SetIcon(fDocument->Icon()); diff --git a/src/apps/icon-o-matic/document/Icon.cpp b/src/apps/icon-o-matic/document/Icon.cpp index 96a56e5b1c..4b6a42b033 100644 --- a/src/apps/icon-o-matic/document/Icon.cpp +++ b/src/apps/icon-o-matic/document/Icon.cpp @@ -50,7 +50,7 @@ Icon::~Icon() // ShapeAdded void -Icon::ShapeAdded(Shape* shape) +Icon::ShapeAdded(Shape* shape, int32 index) { shape->AddObserver(this); _NotifyAreaInvalidated(shape->Bounds(true)); diff --git a/src/apps/icon-o-matic/document/Icon.h b/src/apps/icon-o-matic/document/Icon.h index e222ed099f..7570fb92b0 100644 --- a/src/apps/icon-o-matic/document/Icon.h +++ b/src/apps/icon-o-matic/document/Icon.h @@ -32,7 +32,7 @@ class Icon : public ShapeContainerListener, virtual ~Icon(); // ShapeContainerListener interface - virtual void ShapeAdded(Shape* shape); + virtual void ShapeAdded(Shape* shape, int32 index); virtual void ShapeRemoved(Shape* shape); // Observer interface diff --git a/src/apps/icon-o-matic/document/IconRenderer.cpp b/src/apps/icon-o-matic/document/IconRenderer.cpp index cb5f0b43f2..82c856915a 100644 --- a/src/apps/icon-o-matic/document/IconRenderer.cpp +++ b/src/apps/icon-o-matic/document/IconRenderer.cpp @@ -12,6 +12,7 @@ #include #include +#include #include "agg_span_gradient.h" #include "agg_span_interpolator_linear.h" @@ -21,16 +22,14 @@ #include "Shape.h" #include "ShapeContainer.h" #include "Style.h" -#include "StyleManager.h" #include "VectorPath.h" using std::nothrow; class StyleHandler { public: - StyleHandler(const StyleManager* styles, - GammaTable& gammaTable) - : fStyles(styles), + StyleHandler(GammaTable& gammaTable) + : fStyles(20), fGammaTable(gammaTable), fTransparent(0, 0, 0, 0), fColor(0, 0, 0, 0) @@ -38,7 +37,7 @@ class StyleHandler { bool is_solid(unsigned styleIndex) const { - Style* style = fStyles->StyleAt(styleIndex); + Style* style = (Style*)fStyles.ItemAt(styleIndex); if (!style) return true; @@ -50,6 +49,11 @@ class StyleHandler { void generate_span(agg::rgba8* span, int x, int y, unsigned len, unsigned styleIndex); + bool AddStyle(Style* style) + { + return fStyles.AddItem((void*)style); + } + private: template void _GenerateGradient(agg::rgba8* span, int x, int y, unsigned len, @@ -57,7 +61,7 @@ private: const agg::rgba8* gradientColors, agg::trans_affine& gradientTransform); - const StyleManager* fStyles; + BList fStyles; GammaTable& fGammaTable; agg::rgba8 fTransparent; agg::rgba8 fColor; @@ -67,7 +71,7 @@ private: const agg::rgba8& StyleHandler::color(unsigned styleIndex) { - Style* style = fStyles->StyleAt(styleIndex); + Style* style = (Style*)fStyles.ItemAt(styleIndex); if (!style) { printf("no style at index: %d!\n", styleIndex); return fTransparent; @@ -87,7 +91,7 @@ void StyleHandler::generate_span(agg::rgba8* span, int x, int y, unsigned len, unsigned styleIndex) { - Style* style = fStyles->StyleAt(styleIndex); + Style* style = (Style*)fStyles.ItemAt(styleIndex); if (!style || !style->Gradient()) { printf("no style/gradient at index: %d!\n", styleIndex); // TODO: memset() span? @@ -178,7 +182,6 @@ StyleHandler::_GenerateGradient(agg::rgba8* span, int x, int y, unsigned len, IconRenderer::IconRenderer(BBitmap* bitmap) : fBitmap(bitmap), fIcon(NULL), - fStyles(StyleManager::Default()), fGammaTable(2.2), @@ -201,6 +204,11 @@ IconRenderer::IconRenderer(BBitmap* bitmap) bitmap->Bounds().IntegerWidth() + 1, bitmap->Bounds().IntegerHeight() + 1, bitmap->BytesPerRow()); + + fBaseRendererPre.clip_box(0, + 0, + fBitmap->Bounds().IntegerWidth(), + fBitmap->Bounds().IntegerHeight()); } // destructor @@ -247,15 +255,18 @@ IconRenderer::SetScale(double scale) void IconRenderer::_Render(const BRect& r) { - fBaseRendererPre.clear(agg::rgba8(0, 0, 0, 0)); - if (!fIcon) return; - fBaseRendererPre.clip_box((int)floorf(r.left), - (int)floorf(r.top), - (int)ceilf(r.right), - (int)ceilf(r.bottom)); +// TODO: fix clip box for "clear" and "apply_gamma_inv" +// fBaseRendererPre.clip_box((int)floorf(r.left), +// (int)floorf(r.top), +// (int)ceilf(r.right), +// (int)ceilf(r.bottom)); + + fBaseRendererPre.clear(agg::rgba8(0, 0, 0, 0)); + + StyleHandler styleHandler(fGammaTable); fRasterizer.reset(); // iterate over the shapes in the icon, @@ -265,8 +276,11 @@ IconRenderer::_Render(const BRect& r) for (int32 i = 0; i < shapeCount; i++) { Shape* shape = fIcon->Shapes()->ShapeAtFast(i); - int32 styleIndex = fStyles->IndexOf(shape->Style()); - fRasterizer.styles(styleIndex, -1); + if (!styleHandler.AddStyle(shape->Style())) { + printf("IconRenderer::_Render() - out of memory\n"); + break; + } + fRasterizer.styles(i, -1); if (fGlobalTransform.is_identity()) { fRasterizer.add_path(shape->VertexSource()); @@ -277,8 +291,6 @@ IconRenderer::_Render(const BRect& r) } } - StyleHandler styleHandler(fStyles, fGammaTable); - agg::render_scanlines_compound(fRasterizer, fScanline, fBinaryScanline, diff --git a/src/apps/icon-o-matic/document/IconRenderer.h b/src/apps/icon-o-matic/document/IconRenderer.h index e6994a7dbf..866d38f309 100644 --- a/src/apps/icon-o-matic/document/IconRenderer.h +++ b/src/apps/icon-o-matic/document/IconRenderer.h @@ -22,7 +22,6 @@ class BBitmap; class BRect; class Icon; -class StyleManager; typedef agg::gamma_lut GammaTable; @@ -58,7 +57,6 @@ class IconRenderer { BBitmap* fBitmap; Icon* fIcon; - StyleManager* fStyles; GammaTable fGammaTable; diff --git a/src/apps/icon-o-matic/generic/command/CommandStack.cpp b/src/apps/icon-o-matic/generic/command/CommandStack.cpp index a6cfb3b401..041e1adb07 100644 --- a/src/apps/icon-o-matic/generic/command/CommandStack.cpp +++ b/src/apps/icon-o-matic/generic/command/CommandStack.cpp @@ -43,7 +43,7 @@ CommandStack::Perform(Command* command) ret = command->Perform(); if (ret == B_OK) - ret = AddCommand(command); + ret = _AddCommand(command); if (ret != B_OK) { // no one else feels responsible... @@ -54,45 +54,6 @@ CommandStack::Perform(Command* command) return ret; } - -// AddCommand -status_t -CommandStack::AddCommand(Command* command) -{ - status_t status = B_ERROR; - if (Lock()) { - if (command && (status = command->InitCheck()) == B_OK) { - // try to collapse commands to a single command - bool add = true; - if (!fUndoHistory.empty()) { - if (Command* top = fUndoHistory.top()) { - if (top->CombineWithNext(command)) { - add = false; - delete command; - } else if (command->CombineWithPrevious(top)) { - fUndoHistory.pop(); - delete top; - } - } - } - if (add) - fUndoHistory.push(command); - - // the redo stack needs to be empty - // as soon as an command was added (also in case of collapsing) - while (!fRedoHistory.empty()) { - delete fRedoHistory.top(); - fRedoHistory.pop(); - } - } - Unlock(); - } - - Notify(); - - return status; -} - // Undo status_t CommandStack::Undo() @@ -219,5 +180,41 @@ CommandStack::IsSaved() return saved; } +// #pragma mark - + +// _AddCommand +status_t +CommandStack::_AddCommand(Command* command) +{ + status_t status = B_OK; + // try to collapse commands to a single command + bool add = true; + if (!fUndoHistory.empty()) { + if (Command* top = fUndoHistory.top()) { + if (top->CombineWithNext(command)) { + add = false; + delete command; + } else if (command->CombineWithPrevious(top)) { + fUndoHistory.pop(); + delete top; + } + } + } + if (add) { + // TODO: check return value and set status + fUndoHistory.push(command); + } + + // the redo stack needs to be empty + // as soon as a command was added (also in case of collapsing) + while (!fRedoHistory.empty()) { + delete fRedoHistory.top(); + fRedoHistory.pop(); + } + + Notify(); + + return status; +} diff --git a/src/apps/icon-o-matic/generic/command/CommandStack.h b/src/apps/icon-o-matic/generic/command/CommandStack.h index e4ddd8091b..0c33a0e377 100644 --- a/src/apps/icon-o-matic/generic/command/CommandStack.h +++ b/src/apps/icon-o-matic/generic/command/CommandStack.h @@ -25,7 +25,6 @@ class CommandStack : public BLocker, virtual ~CommandStack(); status_t Perform(Command* command); - status_t AddCommand(Command* command); status_t Undo(); status_t Redo(); @@ -38,6 +37,7 @@ class CommandStack : public BLocker, bool IsSaved(); private: + status_t _AddCommand(Command* command); typedef stack command_stack; diff --git a/src/apps/icon-o-matic/generic/selection/Selectable.cpp b/src/apps/icon-o-matic/generic/selection/Selectable.cpp index 2b18798900..cfd149ee2b 100644 --- a/src/apps/icon-o-matic/generic/selection/Selectable.cpp +++ b/src/apps/icon-o-matic/generic/selection/Selectable.cpp @@ -8,9 +8,14 @@ #include "Selectable.h" +#include + +#include "Selection.h" + // constructor Selectable::Selectable() - : fSelected(false) + : fSelected(false), + fSelection(NULL) { } @@ -21,8 +26,37 @@ Selectable::~Selectable() // SetSelected void -Selectable::SetSelected(bool selected) +Selectable::SetSelected(bool selected, bool exclusive) { + // NOTE: "exclusive" is only useful when selecting, + // it is ignored when deselecting... + if (selected == fSelected) + return; + + if (fSelection) { + if (selected) + fSelection->Select(this, !exclusive); + else + fSelection->Deselect(this); + } else { + debugger("Selectable needs to know Selection\n"); + } +} + +// SetSelection +void +Selectable::SetSelection(Selection* selection) +{ + fSelection = selection; +} + +// #pragma mark - + +// SetSelected +void +Selectable::_SetSelected(bool selected) +{ + // NOTE: for private use by the Selection object! if (fSelected != selected) { fSelected = selected; SelectedChanged(); diff --git a/src/apps/icon-o-matic/generic/selection/Selectable.h b/src/apps/icon-o-matic/generic/selection/Selectable.h index 3f581bc8e9..364a52aba8 100644 --- a/src/apps/icon-o-matic/generic/selection/Selectable.h +++ b/src/apps/icon-o-matic/generic/selection/Selectable.h @@ -11,6 +11,8 @@ #include +class Selection; + class Selectable { public: Selectable(); @@ -21,11 +23,17 @@ class Selectable { virtual void SelectedChanged() = 0; + // this works only if the Selection is known + void SetSelected(bool selected, + bool exclusive = true); + void SetSelection(Selection* selection); + private: friend class Selection; - void SetSelected(bool selected); + void _SetSelected(bool selected); bool fSelected; + Selection* fSelection; }; #endif // SELECTABLE_H diff --git a/src/apps/icon-o-matic/generic/selection/Selection.cpp b/src/apps/icon-o-matic/generic/selection/Selection.cpp index 6081bb0e1a..03f9137e2a 100644 --- a/src/apps/icon-o-matic/generic/selection/Selection.cpp +++ b/src/apps/icon-o-matic/generic/selection/Selection.cpp @@ -47,7 +47,7 @@ Selection::Select(Selectable* object, bool extend) #endif if (fSelected.AddItem((void*)object)) { - object->SetSelected(true); + object->_SetSelected(true); success = true; Notify(); @@ -77,7 +77,7 @@ Selection::Deselect(Selectable* object) if (!fSelected.RemoveItem((void*)object)) debugger("Selection::Deselect() - " "selected object not within list!"); - object->SetSelected(false); + object->_SetSelected(false); Notify(); } @@ -126,7 +126,7 @@ Selection::_DeselectAllExcept(Selectable* except) for (int32 i = 0; i < count; i++) { Selectable* object = (Selectable*)fSelected.ItemAtFast(i); if (object != except) { - object->SetSelected(false); + object->_SetSelected(false); notify = true; } else { containedExcept = true; diff --git a/src/apps/icon-o-matic/gui/ShapeListView.cpp b/src/apps/icon-o-matic/gui/ShapeListView.cpp index d1f3b1cf70..d761a5ca0c 100644 --- a/src/apps/icon-o-matic/gui/ShapeListView.cpp +++ b/src/apps/icon-o-matic/gui/ShapeListView.cpp @@ -8,6 +8,7 @@ #include "ShapeListView.h" +#include #include #include @@ -16,10 +17,15 @@ #include #include +#include "CommandStack.h" +#include "MoveShapesCommand.h" +#include "RemoveShapesCommand.h" #include "Shape.h" #include "Observer.h" #include "Selection.h" +using std::nothrow; + class ShapeListItem : public SimpleItem, public Observer { public: @@ -90,7 +96,8 @@ ShapeListView::ShapeListView(BRect frame, NULL, B_MULTIPLE_SELECTION_LIST), fMessage(message), fShapeContainer(NULL), - fSelection(NULL) + fSelection(NULL), + fCommandStack(NULL) { SetDragCommand(MSG_DRAG_SHAPE); SetTarget(target); @@ -178,11 +185,35 @@ ShapeListView::SetDropTargetRect(const BMessage* message, BPoint where) SimpleListView::SetDropTargetRect(message, where); } +// #pragma mark - + // MoveItems void ShapeListView::MoveItems(BList& items, int32 toIndex) { - SimpleListView::MoveItems(items, toIndex); + if (!fCommandStack || !fShapeContainer) + return; + + int32 count = items.CountItems(); + Shape** shapes = new (nothrow) Shape*[count]; + if (!shapes) + return; + + for (int32 i = 0; i < count; i++) { + ShapeListItem* item + = dynamic_cast((BListItem*)items.ItemAtFast(i)); + shapes[i] = item ? item->shape : NULL; + } + + MoveShapesCommand* command + = new (nothrow) MoveShapesCommand(fShapeContainer, + shapes, count, toIndex); + if (!command) { + delete[] shapes; + return; + } + + fCommandStack->Perform(command); } // CopyItems @@ -190,16 +221,23 @@ void ShapeListView::CopyItems(BList& items, int32 toIndex) { MoveItems(items, toIndex); - // copy operation not allowed -> ?!? - // TODO: what about clips that reference the same file but - // with different "in/out points" + // TODO: allow copying items } // RemoveItemList void -ShapeListView::RemoveItemList(BList& indices) +ShapeListView::RemoveItemList(BList& indexList) { - // TODO: allow removing items + if (!fCommandStack || !fShapeContainer) + return; + + int32 count = indexList.CountItems(); + const int32* indices = (int32*)indexList.Items(); + + RemoveShapesCommand* command + = new (nothrow) RemoveShapesCommand(fShapeContainer, + indices, count); + fCommandStack->Perform(command); } // CloneItem @@ -217,7 +255,7 @@ ShapeListView::CloneItem(int32 index) const // ShapeAdded void -ShapeListView::ShapeAdded(Shape* shape) +ShapeListView::ShapeAdded(Shape* shape, int32 index) { // NOTE: we are in the thread that messed with the // ShapeContainer, so no need to lock the @@ -228,7 +266,7 @@ ShapeListView::ShapeAdded(Shape* shape) // NOTE: shapes are always added at the end // of the list, so the sorting is synced... - _AddShape(shape); + _AddShape(shape, index); UnlockLooper(); } @@ -278,7 +316,7 @@ ShapeListView::SetShapeContainer(ShapeContainer* container) int32 count = fShapeContainer->CountShapes(); for (int32 i = 0; i < count; i++) - _AddShape(fShapeContainer->ShapeAtFast(i)); + _AddShape(fShapeContainer->ShapeAtFast(i), i); // fShapeContainer->ReadUnlock(); } @@ -290,14 +328,21 @@ ShapeListView::SetSelection(Selection* selection) fSelection = selection; } +// SetCommandStack +void +ShapeListView::SetCommandStack(CommandStack* stack) +{ + fCommandStack = stack; +} + // #pragma mark - // _AddShape bool -ShapeListView::_AddShape(Shape* shape) +ShapeListView::_AddShape(Shape* shape, int32 index) { if (shape) - return AddItem(new ShapeListItem(shape, this)); + return AddItem(new ShapeListItem(shape, this), index); return false; } diff --git a/src/apps/icon-o-matic/gui/ShapeListView.h b/src/apps/icon-o-matic/gui/ShapeListView.h index f7dd5f0f1e..1550075726 100644 --- a/src/apps/icon-o-matic/gui/ShapeListView.h +++ b/src/apps/icon-o-matic/gui/ShapeListView.h @@ -12,6 +12,7 @@ #include "ListViews.h" #include "ShapeContainer.h" +class CommandStack; class Shape; class ShapeListItem; class Selection; @@ -43,15 +44,16 @@ class ShapeListView : public SimpleListView, virtual BListItem* CloneItem(int32 atIndex) const; // ShapeContainerListener interface - virtual void ShapeAdded(Shape* shape); + virtual void ShapeAdded(Shape* shape, int32 index); virtual void ShapeRemoved(Shape* shape); // ShapeListView void SetShapeContainer(ShapeContainer* container); void SetSelection(Selection* selection); + void SetCommandStack(CommandStack* stack); private: - bool _AddShape(Shape* shape); + bool _AddShape(Shape* shape, int32 index); bool _RemoveShape(Shape* shape); ShapeListItem* _ItemForShape(Shape* shape) const; @@ -61,6 +63,7 @@ class ShapeListView : public SimpleListView, ShapeContainer* fShapeContainer; Selection* fSelection; + CommandStack* fCommandStack; }; #endif // SHAPE_LIST_VIEW_H diff --git a/src/apps/icon-o-matic/shape/Shape.cpp b/src/apps/icon-o-matic/shape/Shape.cpp index a467f415ad..614388eb7f 100644 --- a/src/apps/icon-o-matic/shape/Shape.cpp +++ b/src/apps/icon-o-matic/shape/Shape.cpp @@ -34,6 +34,40 @@ Shape::Shape(::Style* style) fStyle->Acquire(); } +// constructor +Shape::Shape(const Shape& other) + : Observable(), + Referenceable(), + PathContainerListener(), + + fPaths(new (nothrow) PathContainer(false)), + fStyle(other.fStyle), + + fPathSource(fPaths), + fTransformers(4), + + fLastBounds(0, 0, -1, -1), + + fName(other.fName) +{ + if (fPaths) { + fPaths->AddListener(this); + // copy the path references from + // the other shape + if (other.fPaths) { + int32 count = other.fPaths->CountPaths(); + for (int32 i = 0; i < count; i++) { + if (!fPaths->AddPath(other.fPaths->PathAtFast(i))) + break; + } + } + } + // TODO: clone vertex transformers + + if (fStyle) + fStyle->Acquire(); +} + // destructor Shape::~Shape() { diff --git a/src/apps/icon-o-matic/shape/Shape.h b/src/apps/icon-o-matic/shape/Shape.h index 6b1a024749..72b2585b0b 100644 --- a/src/apps/icon-o-matic/shape/Shape.h +++ b/src/apps/icon-o-matic/shape/Shape.h @@ -21,6 +21,7 @@ class Shape : public Observable, public PathContainerListener { public: Shape(::Style* style); + Shape(const Shape& other); virtual ~Shape(); // PathContainerListener interface diff --git a/src/apps/icon-o-matic/shape/ShapeContainer.cpp b/src/apps/icon-o-matic/shape/ShapeContainer.cpp index de939ad6ab..88d35689dc 100644 --- a/src/apps/icon-o-matic/shape/ShapeContainer.cpp +++ b/src/apps/icon-o-matic/shape/ShapeContainer.cpp @@ -50,6 +50,13 @@ ShapeContainer::~ShapeContainer() // AddShape bool ShapeContainer::AddShape(Shape* shape) +{ + return AddShape(shape, CountShapes()); +} + +// AddShape +bool +ShapeContainer::AddShape(Shape* shape, int32 index) { if (!shape) return false; @@ -58,8 +65,8 @@ ShapeContainer::AddShape(Shape* shape) if (HasShape(shape)) return false; - if (fShapes.AddItem((void*)shape)) { - _NotifyShapeAdded(shape); + if (fShapes.AddItem((void*)shape, index)) { + _NotifyShapeAdded(shape, index); return true; } @@ -114,6 +121,13 @@ ShapeContainer::HasShape(Shape* shape) const return fShapes.HasItem((void*)shape); } +// IndexOf +int32 +ShapeContainer::IndexOf(Shape* shape) const +{ + return fShapes.IndexOf((void*)shape); +} + // ShapeAt Shape* ShapeContainer::ShapeAt(int32 index) const @@ -165,14 +179,14 @@ ShapeContainer::_MakeEmpty() // _NotifyShapeAdded void -ShapeContainer::_NotifyShapeAdded(Shape* shape) const +ShapeContainer::_NotifyShapeAdded(Shape* shape, int32 index) const { BList listeners(fListeners); int32 count = listeners.CountItems(); for (int32 i = 0; i < count; i++) { ShapeContainerListener* listener = (ShapeContainerListener*)listeners.ItemAtFast(i); - listener->ShapeAdded(shape); + listener->ShapeAdded(shape, index); } } diff --git a/src/apps/icon-o-matic/shape/ShapeContainer.h b/src/apps/icon-o-matic/shape/ShapeContainer.h index 37b001c4c2..f547610ac2 100644 --- a/src/apps/icon-o-matic/shape/ShapeContainer.h +++ b/src/apps/icon-o-matic/shape/ShapeContainer.h @@ -18,7 +18,7 @@ class ShapeContainerListener { ShapeContainerListener(); virtual ~ShapeContainerListener(); - virtual void ShapeAdded(Shape* shape) = 0; + virtual void ShapeAdded(Shape* shape, int32 index) = 0; virtual void ShapeRemoved(Shape* shape) = 0; }; @@ -28,6 +28,7 @@ class ShapeContainer { virtual ~ShapeContainer(); bool AddShape(Shape* shape); + bool AddShape(Shape* shape, int32 index); bool RemoveShape(Shape* shape); Shape* RemoveShape(int32 index); @@ -35,6 +36,7 @@ class ShapeContainer { int32 CountShapes() const; bool HasShape(Shape* shape) const; + int32 IndexOf(Shape* shape) const; Shape* ShapeAt(int32 index) const; Shape* ShapeAtFast(int32 index) const; @@ -46,7 +48,8 @@ class ShapeContainer { private: void _MakeEmpty(); - void _NotifyShapeAdded(Shape* shape) const; + void _NotifyShapeAdded(Shape* shape, + int32 index) const; void _NotifyShapeRemoved(Shape* shape) const; BList fShapes; diff --git a/src/apps/icon-o-matic/shape/commands/MoveShapesCommand.cpp b/src/apps/icon-o-matic/shape/commands/MoveShapesCommand.cpp new file mode 100644 index 0000000000..c347a354f5 --- /dev/null +++ b/src/apps/icon-o-matic/shape/commands/MoveShapesCommand.cpp @@ -0,0 +1,157 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "MoveShapesCommand.h" + +#include +#include + +#include "ShapeContainer.h" +#include "Shape.h" + +using std::nothrow; + +// constructor +MoveShapesCommand::MoveShapesCommand(ShapeContainer* container, + Shape** shapes, + int32 count, + int32 toIndex) + : Command(), + fContainer(container), + fShapes(shapes), + fIndices(count > 0 ? new (nothrow) int32[count] : NULL), + fToIndex(toIndex), + fCount(count) +{ + if (!fContainer || !fShapes || !fIndices) + return; + + // init original shape indices and + // adjust toIndex compensating for items that + // are removed before that index + int32 itemsBeforeIndex = 0; + for (int32 i = 0; i < fCount; i++) { + fIndices[i] = fContainer->IndexOf(fShapes[i]); + if (fIndices[i] >= 0 && fIndices[i] < fToIndex) + itemsBeforeIndex++; + } + fToIndex -= itemsBeforeIndex; +} + +// destructor +MoveShapesCommand::~MoveShapesCommand() +{ + delete[] fShapes; + delete[] fIndices; +} + +// InitCheck +status_t +MoveShapesCommand::InitCheck() +{ + if (!fContainer || !fShapes || !fIndices) + return B_NO_INIT; + + // analyse the move, don't return B_OK in case + // the container state does not change... + + int32 index = fIndices[0]; + // NOTE: fIndices == NULL if fCount < 1 + + if (index != fToIndex) { + // a change is guaranteed + return B_OK; + } + + // the insertion index is the same as the index of the first + // moved item, a change only occures if the indices of the + // moved items is not contiguous + bool isContiguous = true; + for (int32 i = 1; i < fCount; i++) { + if (fIndices[i] != index + 1) { + isContiguous = false; + break; + } + index = fIndices[i]; + } + if (isContiguous) { + // the container state will not change because of the move + return B_ERROR; + } + + return B_OK; +} + +// Perform +status_t +MoveShapesCommand::Perform() +{ + status_t ret = B_OK; + + // remove shapes from container + for (int32 i = 0; i < fCount; i++) { + if (fShapes[i] && !fContainer->RemoveShape(fShapes[i])) { + ret = B_ERROR; + break; + } + } + if (ret < B_OK) + return ret; + + // add shapes to container at the insertion index + int32 index = fToIndex; + for (int32 i = 0; i < fCount; i++) { + if (fShapes[i] && !fContainer->AddShape(fShapes[i], index++)) { + ret = B_ERROR; + break; + } + } + + return ret; +} + +// Undo +status_t +MoveShapesCommand::Undo() +{ + status_t ret = B_OK; + + // remove shapes from container + for (int32 i = 0; i < fCount; i++) { + if (fShapes[i] && !fContainer->RemoveShape(fShapes[i])) { + ret = B_ERROR; + break; + } + } + if (ret < B_OK) + return ret; + + // add shapes to container at remembered indices + for (int32 i = 0; i < fCount; i++) { + if (fShapes[i] && !fContainer->AddShape(fShapes[i], fIndices[i])) { + ret = B_ERROR; + break; + } + } + + return ret; +} + +// GetName +void +MoveShapesCommand::GetName(BString& name) +{ +// if (fCount > 1) +// name << _GetString(MOVE_MODIFIERS, "Move Shapes"); +// else +// name << _GetString(MOVE_MODIFIER, "Move Shape"); + if (fCount > 1) + name << "Move Shapes"; + else + name << "Move Shape"; +} diff --git a/src/apps/icon-o-matic/shape/commands/MoveShapesCommand.h b/src/apps/icon-o-matic/shape/commands/MoveShapesCommand.h new file mode 100644 index 0000000000..bf6621613a --- /dev/null +++ b/src/apps/icon-o-matic/shape/commands/MoveShapesCommand.h @@ -0,0 +1,41 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#ifndef MOVE_SHAPES_COMMAND_H +#define MOVE_SHAPES_COMMAND_H + +#include "Command.h" + +class Shape; +class ShapeContainer; + +class MoveShapesCommand : public Command { + public: + MoveShapesCommand( + ShapeContainer* container, + Shape** shapes, + int32 count, + int32 toIndex); + virtual ~MoveShapesCommand(); + + virtual status_t InitCheck(); + + virtual status_t Perform(); + virtual status_t Undo(); + + virtual void GetName(BString& name); + + private: + ShapeContainer* fContainer; + Shape** fShapes; + int32* fIndices; + int32 fToIndex; + int32 fCount; +}; + +#endif // MOVE_SHAPES_COMMAND_H diff --git a/src/apps/icon-o-matic/shape/commands/RemoveShapesCommand.cpp b/src/apps/icon-o-matic/shape/commands/RemoveShapesCommand.cpp new file mode 100644 index 0000000000..6f86fc3c4a --- /dev/null +++ b/src/apps/icon-o-matic/shape/commands/RemoveShapesCommand.cpp @@ -0,0 +1,105 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "RemoveShapesCommand.h" + +#include +#include +#include + +#include "ShapeContainer.h" +#include "Shape.h" + +using std::nothrow; + +// constructor +RemoveShapesCommand::RemoveShapesCommand(ShapeContainer* container, + const int32* indices, + int32 count) + : Command(), + fContainer(container), + fShapes(count > 0 ? new (nothrow) Shape*[count] : NULL), + fIndices(count > 0 ? new (nothrow) int32[count] : NULL), + fCount(count), + fShapesRemoved(false) +{ + if (!fContainer || !fShapes || !fIndices) + return; + + memcpy(fIndices, indices, sizeof(int32) * fCount); + for (int32 i = 0; i < fCount; i++) + fShapes[i] = fContainer->ShapeAt(fIndices[i]); +} + +// destructor +RemoveShapesCommand::~RemoveShapesCommand() +{ + if (fShapesRemoved && fShapes) { + for (int32 i = 0; i < fCount; i++) + delete fShapes[i]; + } + delete[] fShapes; + delete[] fIndices; +} + +// InitCheck +status_t +RemoveShapesCommand::InitCheck() +{ + return fContainer && fShapes && fIndices ? B_OK : B_NO_INIT; +} + +// Perform +status_t +RemoveShapesCommand::Perform() +{ + status_t ret = B_OK; + + // remove shapes from container + for (int32 i = 0; i < fCount; i++) { + if (fShapes[i] && !fContainer->RemoveShape(fShapes[i])) { + ret = B_ERROR; + break; + } + } + fShapesRemoved = true; + + return ret; +} + +// Undo +status_t +RemoveShapesCommand::Undo() +{ + status_t ret = B_OK; + + // add shapes to container at remembered indices + for (int32 i = 0; i < fCount; i++) { + if (fShapes[i] && !fContainer->AddShape(fShapes[i], fIndices[i])) { + ret = B_ERROR; + break; + } + } + fShapesRemoved = false; + + return ret; +} + +// GetName +void +RemoveShapesCommand::GetName(BString& name) +{ +// if (fCount > 1) +// name << _GetString(MOVE_MODIFIERS, "Move Shapes"); +// else +// name << _GetString(MOVE_MODIFIER, "Move Shape"); + if (fCount > 1) + name << "Remove Shapes"; + else + name << "Remove Shape"; +} diff --git a/src/apps/icon-o-matic/shape/commands/RemoveShapesCommand.h b/src/apps/icon-o-matic/shape/commands/RemoveShapesCommand.h new file mode 100644 index 0000000000..8ed56dbcc0 --- /dev/null +++ b/src/apps/icon-o-matic/shape/commands/RemoveShapesCommand.h @@ -0,0 +1,40 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#ifndef REMOVE_SHAPES_COMMAND_H +#define REMOVE_SHAPES_COMMAND_H + +#include "Command.h" + +class Shape; +class ShapeContainer; + +class RemoveShapesCommand : public Command { + public: + RemoveShapesCommand( + ShapeContainer* container, + const int32* indices, + int32 count); + virtual ~RemoveShapesCommand(); + + virtual status_t InitCheck(); + + virtual status_t Perform(); + virtual status_t Undo(); + + virtual void GetName(BString& name); + + private: + ShapeContainer* fContainer; + Shape** fShapes; + int32* fIndices; + int32 fCount; + bool fShapesRemoved; +}; + +#endif // REMOVE_SHAPES_COMMAND_H